perf(node-http-handler): replace per-request checkSocketUsage timer with shared interval#1882
Open
TrevorBurnham wants to merge 1 commit intosmithy-lang:mainfrom
Open
perf(node-http-handler): replace per-request checkSocketUsage timer with shared interval#1882TrevorBurnham wants to merge 1 commit intosmithy-lang:mainfrom
TrevorBurnham wants to merge 1 commit intosmithy-lang:mainfrom
Conversation
…ith shared interval
kuhe
reviewed
Feb 24, 2026
|
|
||
| if ( | ||
| (httpMax === Infinity || httpMax === undefined) && | ||
| (httpsMax === Infinity || httpsMax === undefined) |
Contributor
There was a problem hiding this comment.
this won't activate much, since someone not making http requests won't specify http configuration
| }, warningTimeout); | ||
|
|
||
| if (this.socketWarningInterval.unref) { | ||
| this.socketWarningInterval.unref(); |
Contributor
There was a problem hiding this comment.
can be checked call ?.unref()
| * at the call site's setTimeout wrapper. The warning will be cancelled | ||
| * if the request finishes in a reasonable amount of time regardless | ||
| * of socket saturation. | ||
| * That is why this check runs on a shared interval rather than |
Contributor
There was a problem hiding this comment.
This interval would need a minimum period, but that is beside the point.
The interval fails to let batch traffic resolve when it fires at an inconvenient time.
If switching to an interval, it should warn on monotonic growth over time rather than using the existing criteria.
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.
(Previously submitted as #1878. That PR was closed by mistake on my side. Sorry for the churn!)
Problem
Every call to
NodeHttpHandler.handle()creates asetTimeoutthat invokescheckSocketUsage, and clears it when the request resolves or rejects. Under high concurrency, this means thousands of timer allocations and cleanup operations per batch, all for a diagnostic warning that only needs to fire periodically.Solution
Replace the per-request
setTimeout/clearTimeoutpair with a single sharedsetIntervalon theNodeHttpHandlerinstance, lazily created on the firsthandle()call viaensureSocketWarningInterval().The interval checks both the HTTP and HTTPS agents on each tick. The existing 15-second lockout inside
checkSocketUsageprevents log spam, same as before.When both agents have
maxSockets === Infinity, no interval is created at all;checkSocketUsagewould bail out immediately anyway.What changed
node-http-handler.ts:socketWarningIntervalfield (tri-state:undefined→ not yet initialized,null→ not needed,Timeout→ active).ensureSocketWarningInterval()private method.timing.setTimeout+clearTimeoutfromhandle().destroy()clears the interval.updateHttpClientConfig()resets the interval so it re-initializes with the updated config on the nexthandle()call.checkSocketUsagethat referenced the old per-request setTimeout cancellation behavior.node-http-handler.spec.ts:socketAcquisitionWarningTimeouttest to spy onsetIntervalinstead oftiming.setTimeout.vi.spyOn(timing, "setTimeout")to the per-requestrequestTimeouttest (it was implicitly relying on spy state leaked from the previous test).maxSocketsisInfinityhandle()callsdestroy()clears the intervalWhat did NOT change
checkSocketUsagestatic method — identical logic, just called from the interval instead of per-request timers.handle()(connection, request, socket, keepalive) — these are per-request by design and are untouched.socketAcquisitionWarningTimeoutconfig option — still controls the interval delay, same semantics.Benchmark results
Timer creation overhead measured across concurrency levels (5 iterations averaged):
This measures timer creation overhead only. The old approach also incurred per-request
clearTimeoutcleanup cost on every resolve/reject path.Benchmarking steps
Save the following as
benchmark.tsanywhere in the repo and run it withnpx tsx benchmark.ts: