fix: decrement nr_conns on server-initiated close in the ASGI worker (#3661) - #3686
Merged
Conversation
The ASGI protocol shared one _closed flag for two purposes: marking the transport closed (_close_transport) and guarding the connection_lost() cleanup. On a server-initiated close (Connection: close, keepalive timeout, etc.) _close_transport() set _closed=True before asyncio reported the transport loss, so connection_lost() returned early and never decremented worker.nr_conns. The count grew with worker age and every graceful stop waited out the full graceful_timeout. Use a dedicated _conn_lost_handled flag for the connection_lost() idempotency guard so its cleanup (nr_conns decrement, disconnect signalling) always runs exactly once regardless of who initiated the close. Fixes #3661.
benoitc
force-pushed
the
fix/asgi-nr-conns-server-close-3661
branch
from
August 16, 2026 09:37
a84d93f to
e8a9f86
Compare
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.
Supersedes #3664, whose commit is carried over unchanged and still authored by @apoorvdarshan. Fixes #3661.
nr_connsis only decremented inconnection_lost(), behind an idempotence guard keyed on_closed._close_transport()sets_closedbefore asyncio delivers the transport loss, so every close the server starts returns at the guard and leaks one count for good. That coversConnection: closeresponses, keepalive timeouts and error aborts. Client-initiated closes stay balanced becauseconnection_lost()runs first.The early return also skips the rest of the cleanup: the keepalive timer,
reader.feed_eof()and the body receiver'ssignal_disconnect(), so the app is never told the peer has gone (#3484).ASGIWorker._shutdown()pollsnr_connsagainst a deadline, so a leaked count makes every graceful stop run the fullgraceful_timeoutand then warn about connections that are already gone.The guard now uses its own flag, so the decrement and the rest of the cleanup run exactly once whichever side closes first.