Repository navigation
Close persistent HTTP sessions during graceful shutdown - #1447
Merged
burtenshaw merged 18 commits intoOct 26, 2026
Merged
Conversation
This was referenced Oct 27, 2026
Merged
3 of 8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #1437.
Persistent HTTP sessions remained open after normal application shutdown: their MCP contexts, environments and per-session executors were never closed. Shutdown now waits for the idle reaper to finish any cleanup already underway, closes the remaining sessions through
_destroy_session(), and then stops the shared executor.The reaper stops cooperatively so shutdown cannot interrupt cleanup after a session has already been removed from the registry; session-creation cancellation (#1301), forced shutdown and timeout policy remain outside this fix.
Type of Change
Alignment Checklist
.claude/docs/PRINCIPLES.mdand this PR aligns with our principles.claude/docs/INVARIANTS.mdand no invariants are violated/pre-submit-pr(orbash .claude/hooks/lint.shand tests) and addressed all issuesBoth changed files pass usort, Ruff lint and Ruff formatting. The project-wide formatting check on this base reports unrelated formatting/import-order failures, recorded separately during #1436; those files are unchanged here. The full repository test suite was not run.
RFC Status
Test Plan
Six new cases fail before the fix and pass afterward: normal shutdown, continued cleanup after an ordinary close failure, and shutdown while the real idle reaper is inside MCP context cleanup. Each runs with both per-session and shared executors.
The tests create sessions through HTTP inside the actual application lifespan. They retain real in-process FastMCP clients and check disconnection, MCP exit before environment close, constructor-thread affinity, executor shutdown and empty session bookkeeping. A session explicitly closed before shutdown is not closed again. The existing best-effort retry after a failing
close()is preserved.On Python 3.12:
Across these modules, validated in three groups: 134 passed, 1 skipped. The skip is an existing disabled implementation-detail test. No external model, hosted environment or container was used.
Claude Code Review
N/A. Codex was used for investigation, implementation and testing.
Note
Medium Risk
Changes core session lifecycle and shutdown ordering for production HTTP MCP; incorrect teardown could leave resources open or block shutdown, but behavior is covered by new lifespan tests.
Overview
Fixes graceful shutdown so persistent HTTP MCP sessions are torn down instead of leaking MCP contexts, environments, and executors after the app stops.
Shutdown path: FastAPI
on_shutdownnow runs_shutdown_sessions, which cooperatively stops the idle reaper, calls_destroy_sessionfor every remaining session, then shuts down the shared session executor. The reaper uses_reaper_stop_eventandasyncio.wait_foron that event instead of fixedsleepplus task cancellation, so stop returns promptly and in-flight reaper cleanup can finish before shutdown proceeds.Tests: New
TestHTTPMCPSessionShutdowncovers lifespan shutdown (MCP disconnect, teardown order, executor shutdown), cleanup whenclose()fails, and shutdown while the reaper is mid–MCP exit; reaper stop is asserted to complete without cancellation.Reviewed by Cursor Bugbot for commit 3987779. Bugbot is set up for automated code reviews on this repo. Configure here.