fix: prevent race condition between onEnd and onTrailers in HTTP/2 client (#5216)#5343
Open
mcollina wants to merge 3 commits into
Open
fix: prevent race condition between onEnd and onTrailers in HTTP/2 client (#5216)#5343mcollina wants to merge 3 commits into
mcollina wants to merge 3 commits into
Conversation
…ient
When the 'end' event fires before 'trailers' (observed on Windows),
onEnd would call onResponseEnd({}) with empty trailers and remove
the 'trailers' listener, causing the flaky test in issue #5216.
Fix: in onEnd, check if the 'trailers' listener is still registered.
If so, defer completion to onTrailers via a process.nextTick fallback.
This ensures onTrailers gets a chance to pass the actual trailers,
regardless of event ordering.
Adapts the test 'Should remove request-owned http2 stream listeners
after completion' to check listener counts after the async fallback.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #5343 +/- ##
=======================================
Coverage 93.23% 93.24%
=======================================
Files 110 110
Lines 36631 36678 +47
=======================================
+ Hits 34154 34200 +46
- Misses 2477 2478 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
Description
Fixes a flaky test
test/http2-trailers.js(issue #5216) caused by a race condition between theonEndandonTrailersevent handlers in the HTTP/2 client (lib/dispatcher/client-h2.js).Root Cause
On Windows, Node.js can emit
'end'before'trailers'(reversing the expected event order). WhenonEndfires first, it callsrequest.onResponseEnd({})with empty trailers and removes the'trailers'listener viareleaseRequestStream(stream). By the timeonTrailersfires, it seesrequest.completed === trueand returns without passing the actual trailers. The test assertiont.strictEqual(trailers['x-trailer'], 'hello')then fails.Fix
Consolidate all response completion and stream cleanup into
onRequestStreamClose, which fires on the stream's natural'close'event (always after'end'and'trailers'). Individual event handlers now only store state:onEnd: setsstate.pendingEnd = true, returns — noreleaseRequestStream, noonResponseEndonTrailers: stores trailers instate.trailers, removes'data'listener, returns — noreleaseRequestStream, noonResponseEndonTimeout/onError/onFrameError: abort the request, return — noreleaseRequestStreamonRequestStreamClose: callsreleaseRequestStream, then completes the response withstate.trailers || {}ifpendingEnd && !aborted && !completedThis eliminates the
deferredCompletionflag, theprocess.nextTickfallback, and all complex branching — the stream lifecycle ('end'→'trailers'→'close') handles everything regardless of event ordering.Test Adaptation
Both tests in
test/http2-late-data.jsnow emit'close'after'end'to triggeronRequestStreamClose, which is the natural event order in real HTTP/2 streams.Testing
All 295 HTTP/2 and client tests pass, including
test/http2-trailers.js.