You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
preserve the caller-provided abort signal when rewriting browser requests for direct VM routing
retain signals supplied through both RequestInit and Request inputs
add a deterministic regression test that fails with the previous dependent signal
why
Reconstructing a Request creates a dependent signal. Passing that derived signal to the routed fetch can intermittently leave streamed response reads blocked after the caller aborts.
tests
yarn test --runInBand
yarn lint
yarn build
Note
Medium Risk
Touches fetch routing for live SSE/telemetry streams where incorrect abort handling caused intermittent hangs; change is narrow but behavior-critical for cancellation.
Overview
Direct-to-VM browser routing no longer forwards the dependentAbortSignal from the reconstructed Request when issuing the routed innerFetch. buildRoutedInit now takes the original input and sets signal from originalInit?.signal, or from the caller’s Request when input is a Request, so aborts on allowlisted paths like telemetry/stream propagate to the underlying fetch and streamed reads can unwind after cancel.
A regression test asserts the routed fetch receives the same signal reference for both URL + RequestInit and Request call shapes.
Reviewed by Cursor Bugbot for commit 2eec02c. Bugbot is set up for automated code reviews on this repo. Configure here.
Post-merge verification. I reproduced the original failure independently and re-tested this change against it. The fix is correct.
What I verified on 2eec02c:
tsc --noEmit clean, full suite 405 passed. Reverting just the signal: line makes the new test fail (✕ preserves the caller abort signal for routed requests), so the guard is real rather than vacuous.
Real end-to-end A/B with a warm route cache and a forced GC, aborting an established SSE stream: 10/10 hung before this change, 0/10 after. Against a live streaming backend under three concurrent sessions cycling open-then-abort: 3/54 hung before, 0/60 after. A longer randomized run on the pre-fix code hung 37/170.
Choosing an identity assertion over a behavioral one was the right call. A hang-reproducing test needs --expose-gc, which jest.config.ts does not set, so it would have passed either way.
Two follow-ups:
This also repairs stream.controller.abort(), the documented cancellation idiom, which was equally dead: 10/10 hung before, 0/10 after. Worth noting in the changelog, since callers who never passed a signal were affected too and may not realize this covers them.
The Request-input branch preserves signal identity but not abort survival, so the summary line overstates it slightly. routingFetch(new Request(url, {signal})) still hangs 10/10 with this change applied, because input.signal is itself a dependent signal owned by the caller's Request; assign that Request to a variable first and it is 0/10. The test asserts routedSignal === request.signal, which passes either way, so it does not distinguish the two. Nothing to fix in the SDK, since fetchWithTimeout always passes a string URL and never reaches that branch, but the claim and the test both read stronger than the behavior.
Release status: 0.87.0 on npm does not contain this fix, so anyone hitting the original hang is still affected until #163 (0.87.1) merges.
the original test now says exactly what it proves: signal identity for RequestInit and Request inputs
added coverage that stream.controller.abort() retains the exact signal passed to the routed telemetry request
updated the 0.87.1 changelog to call out stream.controller.abort() cancellation
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
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.
summary
RequestInitandRequestinputswhy
Reconstructing a
Requestcreates a dependent signal. Passing that derived signal to the routed fetch can intermittently leave streamed response reads blocked after the caller aborts.tests
yarn test --runInBandyarn lintyarn buildNote
Medium Risk
Touches fetch routing for live SSE/telemetry streams where incorrect abort handling caused intermittent hangs; change is narrow but behavior-critical for cancellation.
Overview
Direct-to-VM browser routing no longer forwards the dependent
AbortSignalfrom the reconstructedRequestwhen issuing the routedinnerFetch.buildRoutedInitnow takes the originalinputand setssignalfromoriginalInit?.signal, or from the caller’sRequestwheninputis aRequest, so aborts on allowlisted paths liketelemetry/streampropagate to the underlying fetch and streamed reads can unwind after cancel.A regression test asserts the routed fetch receives the same signal reference for both URL +
RequestInitandRequestcall shapes.Reviewed by Cursor Bugbot for commit 2eec02c. Bugbot is set up for automated code reviews on this repo. Configure here.