fix(h1): stop unref'ing the idle socket validation immediate - #5609
Open
marko1olo wants to merge 1 commit into
Open
fix(h1): stop unref'ing the idle socket validation immediate#5609marko1olo wants to merge 1 commit into
marko1olo wants to merge 1 commit into
Conversation
Reusing an idle keep-alive socket can stall for up to a fast-timers tick (~500ms) before the request reaches the wire. With a pool of one connection and a 10ms server, six sequential requests take over a second instead of the ~60ms the server accounts for. `scheduleIdleSocketValidation` moved from an unref'd `setTimeout(..., 0)` to `setImmediate` in nodejs#5499, and the `unref?.()` came along with it. An unref'd immediate does not hold the loop open, so on an otherwise idle loop the check phase can be reached only once the next fast-timers tick wakes things up, and the queued request waits for it. The request the validation exists for is already queued at that point, so there is nothing to keep alive artificially: the immediate is a one-shot that runs on the very next check phase and `clearIdleSocketValidation` cancels it when the socket goes away. test/issue-5600.js fails on the current code with a slowest request around 425ms and passes with the immediate left ref'd; on this machine the six requests go from 1095/1565/2045ms across runs to 122/137/219ms. Signed-off-by: marko1olo <marko1olo@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5609 +/- ##
=======================================
Coverage 93.49% 93.49%
=======================================
Files 110 110
Lines 38281 38302 +21
=======================================
+ Hits 35789 35811 +22
+ Misses 2492 2491 -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.
This relates to...
Fixes #5600.
Rationale
Reusing an idle keep-alive socket stalls for up to a fast-timers tick before the request reaches the wire. With a pool of one connection against a 10 ms server, six sequential requests take over a second instead of the ~60 ms the server accounts for.
scheduleIdleSocketValidationmoved from an unref'dsetTimeout(..., 0)tosetImmediatein #5499, and theunref?.()came along with it. An unref'd immediate does not hold the loop open, so on an otherwise idle loop the check phase is reached only once the next fast-timers tick wakes things up, and the queued request waits for that.By the time the validation is scheduled, the request it exists for is already queued, so there is nothing to keep alive artificially. The immediate is a one-shot that runs on the very next check phase, and
clearIdleSocketValidationcancels it when the socket goes away, so leaving it ref'd cannot delay process exit by more than that one turn — unlike thesetTimeoutthis was inherited from.Measured on Windows with Node 24, six sequential requests through a single-connection pool:
Changes
lib/dispatcher/client-h1.js: drop theunref?.()on the idle socket validation immediate.test/issue-5600.js: the reproduction from the issue, asserting the slowest of six sequential requests on a single-connection pool stays well under a fast-timers tick. It fails on currentmainwith a slowest request around 425 ms.npx borp --timeout 180000 --expose-gc -p "test/*.js"is 1439 passing here. The one failure in that run istest/http2-dispatcher.js"Should send http2 PING frames", which fails about two runs in three on unpatchedmainon this machine as well — unrelated to HTTP/1, and I have a separate branch for it if that is wanted.Features
Bug Fixes
Status