Keep pooled HTTP/2 connections alive when their dialer exits - #939
Merged
Merged
Conversation
A pooled HTTP/2 connection stayed owned by the caller that dialed it, so
when that caller exited the connection stopped and every other caller's
request on it failed with {error, closed}.
A shared connection now has no owner. hackney shares it before
registering it with the pool, each stream monitors its own caller and is
reset if that caller dies, and the connection closes itself once it has
had no open stream for the pool timeout. The pool stays a registry and
releases the per-host slot when the connection stops. Connections that
are not pooled keep their owner.
Unregistering a checked-out HTTP/2 connection also dropped the pool's
monitor on it, so its per-host slot was never released; it now keeps
the monitor.
Reported and diagnosed by @smartinio in #937, whose per-stream tracking
this builds on.
The handler answered the stream the client had just reset. On slow runners that response crossed the RST_STREAM, and h2 drops a header block for a reset stream without decoding it, so the HPACK tables fell out of sync and the next response on the connection failed to decode. That is an h2 issue of its own; this test only needs the stream reset.
This was referenced Sep 21, 2026
Merged
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.
Replaces #937. Thanks to @smartinio for reporting this, tracing the cause, and the per-stream tracking this builds on.
A pooled HTTP/2 connection stayed owned by the caller that dialed it. When that caller exited, the connection stopped and every other caller's request on it failed with
{error, closed}.#937 fixed it by making the pool the owner, which then needed synchronous registration with deadlines, retiring busy connections and polling for reuse. This takes a smaller route: a shared connection has no owner and stays under
hackney_conn_sup. Each stream monitors its own caller and is reset if that caller dies. The connection closes itself once it has had no open stream for the pooltimeout. The pool stays a registry, and registration is still a cast.It also fixes a slot leak: unregistering a checked-out HTTP/2 connection dropped the pool's monitor on it, so its per-host slot was never released when it stopped.
Connections that are not pooled keep their owner. A streaming upload still blocks its shared connection (
streaming_body); moving uploads to per-stream state is a separate change.