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
+18
View File
@@ -237,6 +237,24 @@ They do **not** affect connections to internal services (Ollama, Qdrant, Unstruc
---
## Health & Readiness Probes
The server exposes two Kubernetes probe endpoints:
- `GET /health/live` — liveness. Returns `200` whenever the process is running. It does **not** check external dependencies, so it never restarts the Pod on an upstream blip.
- `GET /health/ready` — readiness. Gates **only** on local configuration (`NEXTCLOUD_HOST` set, auth mode configured). External-dependency reachability (Nextcloud `status.php`, Qdrant `/readyz`) is reported in the response body for observability but is **non-gating**.
> **Why non-gating (Deck #302):** the server typically runs as a single replica per tenant. If readiness failed whenever Nextcloud or Qdrant had a transient blip, the only Pod would be pulled from its Service, leaving the gateway with no upstream — turning a *degraded* dependency into a *total* outage and dropping every MCP client's streamable-HTTP session. Dependency health is instead refreshed by a background loop and cached, so the probe path performs no external I/O.
```dotenv
# Cadence (seconds) for the background dependency-health refresh loop (default: 15)
HEALTH_READY_REFRESH_INTERVAL=15
```
The probe reports each dependency under `checks` (`ok` / `embedded` / `pending` / `error: ...`); a non-`ok` dependency no longer flips the overall `status` to `not_ready`.
---
## Semantic Search Configuration (Optional)
**New in v0.58.0:** Simplified semantic search configuration with automatic dependency resolution.