Skip to content

Own a direct connection by the process that opened it - #951

Merged
benoitc merged 1 commit into
masterfrom
fix/direct-conn-owner
Sep 26, 2026
Merged

benoitc merged 1 commit into
masterfrom
fix/direct-conn-owner

Conversation

@benoitc

@benoitc benoitc commented Sep 26, 2026 •

Copy link
Copy Markdown
Owner

A connection opened without a pool was started under hackney_conn_sup, so the supervisor was its owner. When the caller was killed, nothing closed it, and with idle_timeout at infinity the socket stayed open until the server closed it. Found in barrel, where a query worker killed at its deadline left its connection open.

The start sites now pass owner => self(), since they run in the caller:

  • hackney:connect_direct/4: request/5 and connect/* with {pool, false}, streamed request bodies, async responses, plain HTTP proxies, and HTTP/2 and HTTP/3 without a pool
  • hackney:start_conn_with_socket_internal/5: CONNECT and SOCKS5 tunnels
  • hackney_h2_stream:establish/2: h2_open/*, so the connection closes even when the stream process is killed before terminate/3

With stream_to set to another process, that process owns the connection. This was already the case (#646) and is now tested. The pool path is unchanged, and set_owner/2,3 still moves ownership.

hackney_direct_owner_tests covers each entry point: kill the opener, then wait for the conn's 'DOWN' and the server-side socket close. No sleeps. 10 of its 12 tests fail on 4.8.1. The stream_to and set_owner tests pass there too, as expected. unpooled_conn_not_shared now asserts the uploader is monitored once, as owner.

Known limit: an HTTP/1.1 conn waiting for a response is blocked in a passive recv, so it sees its owner's death only when the read returns, at the latest after recv_timeout.

A connection opened without a pool was started under hackney_conn_sup and
owned by it, so a killed caller left the connection and its socket open
until the server closed it. connect_direct, start_conn_with_socket and the
h2_open stream now pass owner => self(), so the connection closes when its
opener dies. Pooled connections are unchanged.
@benoitc
benoitc merged commit 45885fa into master Sep 26, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant