fix(h2): keep the connection ref'd while requests are outstanding - #5605
Merged
Conversation
resumeH2() unreffed the socket and the session whenever the peer advertised
SETTINGS_MAX_CONCURRENT_STREAMS = 0, regardless of whether anything was
still queued:
if (client[kSize] === 0 || client[kMaxConcurrentStreams] === 0) {
A peer may legitimately advertise 0 to refuse new streams for a while
(RFC 9113 6.5.2). A request queued behind that owns no handle and arms no
timer of its own, so once the connection was unreffed nothing held the
event loop open: the process exited with status 0 while an awaited request
never settled, and the code after the await never ran.
Unref only when there is genuinely nothing outstanding.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A49JamgF2TkZHu5h58ChUM
Signed-off-by: Matteo Collina <hello@matteocollina.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## v7.x #5605 +/- ##
==========================================
- Coverage 93.17% 93.15% -0.02%
==========================================
Files 112 112
Lines 36751 36755 +4
==========================================
- Hits 34241 34240 -1
- Misses 2510 2515 +5 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
ronag
approved these changes
Jul 29, 2026
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.
resumeH2()unreffed the socket and the session whenever the peer advertisedSETTINGS_MAX_CONCURRENT_STREAMS = 0, regardless of whether anything was still queued:A peer may legitimately advertise
0to refuse new streams for a while (RFC 9113 §6.5.2) — graceful drain, overload shedding, a load balancer draining a backend. A request queued behind that owns no handle and arms no timer of its own, so once the connection was unreffed there was nothing left holding the event loop open.The result is a process that exits with status 0 while an awaited request never settles:
No error, no warning, no non-zero exit code — the code after the
awaitsimply never runs. For a job or a CLI that means silently skipped work reported as success.Unref only when there is genuinely nothing outstanding.
Test
test/http2-max-concurrent-streams-zero-unref.jsdrives a child process whose only live work is the queued request, against a server that drains tomaxConcurrentStreams: 0. Staying alive is the pass condition; exiting 0 is the bug. Verified to fail before this change (the process exited cleanly with a request still outstanding) and pass after.test/+(http2|h2)*.js: 51 pass. Full unit suite: 1304 pass, 0 fail.Note
This makes the failure visible rather than silent — the request itself is still stuck until a stream timeout fires. #5604 (
fix(h2): honour headersTimeout) is what bounds that wait properly; the two are independent but complementary.🤖 Generated with Claude Code
https://claude.ai/code/session_01A49JamgF2TkZHu5h58ChUM