fix(app): cancel readiness loop on lifespan shutdown (review round 2)
_readiness_refresh_loop is started with tg.start_soon and loops forever with no shutdown_event check. anyio waits for start_soon tasks on normal task-group exit rather than cancelling them, so graceful shutdown hung until uvicorn's timeout. Cancel the task group's scope after teardown() to stop the loop and any stragglers, mirroring _maybe_login_flow_cleanup. Also document the cache ttl_seconds startup-override and the inclusive is_stale boundary. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
cc2ce6e853
commit
fc62a30384
@@ -434,6 +434,8 @@ def _clear_vector_sync_state() -> None:
|
||||
# Fallback public URL when NEXTCLOUD_MCP_SERVER_URL is unset (dev/local).
|
||||
_DEFAULT_MCP_SERVER_URL = "http://localhost:8000"
|
||||
|
||||
# Pre-loop default; _readiness_refresh_loop overrides ttl_seconds at startup to
|
||||
# 2x the configured refresh interval, so bumping this value alone has no effect.
|
||||
_readiness_cache = ReadinessCache(ttl_seconds=30.0)
|
||||
|
||||
|
||||
@@ -2186,6 +2188,12 @@ def get_app(transport: str = "streamable-http", enabled_apps: list[str] | None =
|
||||
# Request path must not spawn into a cancelling group.
|
||||
_vector_sync_state.eviction_task_group = None
|
||||
await teardown()
|
||||
# teardown() signals the sync tasks to drain, but the readiness loop
|
||||
# runs forever and has no shutdown_event to observe. anyio waits for
|
||||
# start_soon tasks on normal exit rather than cancelling them, so
|
||||
# without this the lifespan shutdown hangs until uvicorn's graceful
|
||||
# timeout. Cancel the group to stop the loop (and any stragglers).
|
||||
tg.cancel_scope.cancel()
|
||||
|
||||
# Health check endpoints for Kubernetes probes
|
||||
def health_live(request):
|
||||
|
||||
Reference in New Issue
Block a user