fix(health): non-gating readiness probe; shared-task-group lifespan; settings migration

Fixes MCP reconnect timeouts on tenant servers (Deck #302). Three changes:

- /health/ready now gates only on local config. Nextcloud/Qdrant health is
  refreshed by a background loop, cached, and reported but NON-gating, so a
  single-replica tenant Pod is no longer pulled from its Service on a transient
  dependency blip (which dropped every MCP streamable-HTTP session and caused
  reconnect timeouts). The probe path performs no external I/O.
- Refactor starlette_lifespan: collapse the four near-identical per-mode
  task-group + session + yield + teardown skeletons into one shared task group
  that also runs the readiness refresh loop; each mode contributes a
  (start, teardown) pair. eviction_task_group is now always present.
- Migrate app.py off os.getenv: all config is read through dynaconf Settings
  (adds health_ready_refresh_interval, oidc_token_type, oidc_scopes, port).
  Inline/dynamic defaults preserved at each call site.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-10 21:28:19 +02:00
co-authored by Claude Opus 4.8
parent 86ed15f466
commit 6ef7786cec
6 changed files with 420 additions and 227 deletions
+6 -16
View File
@@ -123,14 +123,9 @@ class TestSetupOAuthConfigForMultiUserBasic:
valid_fernet_key = Fernet.generate_key().decode()
# Mock TOKEN_ENCRYPTION_KEY environment variable
mocker.patch(
"os.getenv",
side_effect=lambda k, default=None: {
"TOKEN_ENCRYPTION_KEY": valid_fernet_key,
"NEXTCLOUD_MCP_SERVER_URL": "http://localhost:8000",
}.get(k, default),
)
# Provide the encryption key via settings: the function reads from the
# injected Settings, not os.getenv, after the env->settings migration.
hybrid_auth_settings.token_encryption_key = valid_fernet_key
# Mock httpx.AsyncClient
mock_response = MagicMock()
@@ -273,17 +268,12 @@ class TestSetupOAuthConfigForMultiUserBasic:
self, hybrid_auth_settings, oidc_discovery_response, mocker
):
"""Test using custom OIDC discovery URL."""
# Mock OIDC_DISCOVERY_URL environment variable
# Provide the custom discovery URL via settings: the function reads from
# the injected Settings, not os.getenv, after the env->settings migration.
custom_discovery_url = (
"https://custom.idp.example.com/.well-known/openid-configuration"
)
mocker.patch(
"os.getenv",
side_effect=lambda k, default=None: {
"OIDC_DISCOVERY_URL": custom_discovery_url,
"NEXTCLOUD_MCP_SERVER_URL": "http://localhost:8000",
}.get(k, default),
)
hybrid_auth_settings.oidc_discovery_url = custom_discovery_url
# Mock httpx.AsyncClient
mock_response = MagicMock()