Skip to content

Resend a request once when its pooled connection was closed - #1331

Open
fazxes wants to merge 6 commits into
mainfrom
fazxes/resend-closed-pooled-connections
Open

fazxes wants to merge 6 commits into
mainfrom
fazxes/resend-closed-pooled-connections

Conversation

@fazxes

@fazxes fazxes commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • A request on a pooled connection that the gateway closed while idle now goes out again on a fresh connection, without the "Network interrupted" warning.
  • The same applies to the connection fx opens at launch when the gateway reset it before first use.
  • A failure on a fresh connection, or after the gateway started answering, still shows "Network interrupted" and retries as before.

- A pooled keep-alive connection that the gateway closed while it sat idle failed the next request before any response byte arrived, and fx showed "Network interrupted" on a healthy network. fx now sends that request once more on a fresh connection and shows nothing.
- Only a reused connection that fails while sending, or while reading the response head before any head byte, qualifies. A fresh connection that fails, a response that had started, cancellation, and a wake from sleep are reported as before.
- `HttpPool.openRequest` takes the idle connection itself so it can report reuse, and the resend closes the origin's other idle connections first so it dials fresh.
- The connection fx warms at launch counts as reused, so a warm connection the gateway reset also heals silently. The peer-reset test now resets two connections, so its second reset still lands on a fresh connection that fx reports.
@fazxes fazxes added the type: bug Fixes incorrect behavior label Oct 17, 2026
- A request deadline cancels the socket read or write in place, and std reports it as an ordinary read or write failure. On a reused connection with no response bytes, that looked like a connection the gateway had closed, so the request went out again after the caller gave up. A failure now counts as a closed connection only when the socket says the peer closed it, or the head read ends cleanly.
- A head failure also counts only within five seconds of the send and only when no response byte arrived, including an incomplete TLS record that is still undecrypted.
- The E2E test counts only connections that carried a request, so an unused warm-up connection cannot change its result.
- Time the five-second head window on the boot clock, so a laptop that slept after the send cannot make a late failure look like a quick one.
- Trace the stage, the socket's own error, the received bytes, and the elapsed time for every failure on a reused connection, whether fx resends it or reports it.
- Note that a connection std reuses after another request released it counts as fresh, so its failures are reported.
- Add a loopback test where the gateway starts the response head on a reused connection and then resets it. The request is reported, not resent, and this is the only test where the received-bytes check decides.
- Count the socket buffer only for TLS, where it can hold an undecrypted record. Plain HTTP reads that buffer directly, so the trace counted its bytes twice.
- Trace received bytes and elapsed time only for head failures, where they are measured.
- Set FX_SOUND=0 for the fx processes the closed pooled connection E2E test starts, as tests that spawn fx directly must.
- Require ReadFailed in the reset-after-head test, so a resend that fails fast cannot pass it.
@fazxes
fazxes marked this pull request as ready for review October 17, 2026 09:01

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: bug Fixes incorrect behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant