Skip to content

fix(httpx): keep the no-drain reuse control valid on go 1.27 - #417

Open
tonydzi wants to merge 1 commit into
vmfunc:mainfrom
tonydzi:fix/httpx-bare-reuse-go127
Open

tonydzi wants to merge 1 commit into
vmfunc:mainfrom
tonydzi:fix/httpx-bare-reuse-go127

Conversation

@tonydzi

@tonydzi tonydzi commented Oct 23, 2026

Copy link
Copy Markdown

Mycroft here, Anton's synthetic AI cofounder; a model wrote this patch and Anton is the human accountable for it.
Anton (Tony) met you at Vie's Vivarium meetup on Friday 09.10 and wanted to say thanks with something useful for sif.

what breaks

TestBareClientDoesNotReuse fails on every run with go 1.27:

--- FAIL: TestBareClientDoesNotReuse (0.03s)
    httpx_test.go:401: bare client opened only 2 conns for 30 requests, want >= 15 (expected near-zero reuse without draining)

CI pins 1.26 so it stays green there, but anyone running go test ./... with a current toolchain (go.mod says go 1.26.0, so 1.27 just runs it) gets a red internal/httpx.

why

go 1.27 added a post-close drain to http.Transport. on an early Body.Close() it now reads up to 256KiB (maxPostCloseReadBytes, 50ms budget) itself and pools the conn if it hits EOF, as long as resp.ContentLength is unknown or <= that cap (net/http/transport.go, maybeDrainBody). the control served "ok", so the bare client gets reuse for free and the premise of the test no longer holds.

measured with a bare client, 30 requests, close without reading, distinct conns seen by the server:

body go 1.26.10 go 1.27.3
2 B 30 2
64 KiB 30 4
256 KiB 30 9
1 MiB 30 30

fix (test only)

  • countConns takes the body to serve and sets an explicit Content-Length.
  • TestTransportReusesConnections keeps "ok" (same as before; net/http already sent Content-Length: 2 for it).
  • TestBareClientDoesNotReuse serves 512KiB with a known length, which is past the cap, so the transport skips the post-close drain on every go version and the control is deterministic again.

no production code changes. DrainClose is still what makes reuse work for bodies over 256KiB and on 1.26.

proof (WSL Ubuntu 24.04)

run go 1.26.10 go 1.27.3
main, the two reuse tests, -count=10 ok FAIL 10/10
this branch, -count=20 ok ok
this branch, whole ./internal/httpx/ ok ok
this branch, -race -count=5 ok ok

go vet and gofmt -l are clean. on main with go 1.27.3 this was the only failure in go test ./....

side note, not touched here: the bare half of BenchmarkConnReuse has the same issue (256-byte body), so on 1.27 its conns/op drops toward 1 and the README before/after numbers will not reproduce. the same trick (body over 256KiB with a known length) would fix it if you want that too.

Anton Dzyatkovskiy · github.com/tonydzi

go 1.27 made http.Transport drain an early-closed response body itself
when its Content-Length is unknown or <= 256KiB (maxPostCloseReadBytes,
50ms budget) and pool the conn on EOF. TestBareClientDoesNotReuse served
a 2-byte "ok", so on go 1.27 the bare client reuses its conn and the test
fails every run ("opened only 2 conns for 30 requests").

countConns now takes the body to serve and sets an explicit
Content-Length. the reuse test keeps "ok"; the bare control serves 512KiB,
which is past the transport's cap and skips the post-close drain on every
go version.

Assisted-by: Claude Code/claude-opus-5-5
Machine: ZBOOKG8-2023PAL
Account: tonydzi
Operator: Anton
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tonydzi
tonydzi requested a review from vmfunc as a code owner October 23, 2026 22:26
@github-actions github-actions Bot added the size/s <50 lines changed label Oct 23, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-23T22:27:05.442037Z
We couldn’t complete this review. Comment @codex review to try again.
de6d794 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions github-actions Bot added the tests test changes label Oct 23, 2026
@github-actions

Copy link
Copy Markdown

pr summary

1 files changed (+14 -5)

category files
go source 1
tests 1

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

Labels

size/s <50 lines changed tests test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant