Improve Fetch Stream Handling for Long-lived Streams to Ensure Connection Closure #13996
Open
3 tasks done
Labels
Package: nextjs
Issues related to the Sentry Nextjs SDK
Is there an existing issue for this?
How do you use Sentry?
Self-hosted/on-premise
Which SDK are you using?
@sentry/nextjs
SDK Version
8.33.1 ~ develop (build by myself)
Framework Version
Next 14.2.13
Link to Sentry event
No response
Reproduction Example/SDK Setup
sentry.client.config.ts
sentry.edge.config.ts
sentry.server.config.ts
Steps to Reproduce
Hi Sentry Team,
Thank you for adding the
trackFetchStreamPerformance
option in #13951 and setting it to false by default to resolve #13950. However, I would still like to enable this feature in my project, so I’ve submitted PR #13967 to address the issue.Problem Summary
In my understanding, there are several scenarios where a
fetch
connection ends:AbortController
andAbortSignal
.Response
ReadableStream
s are canceled, prompting the browser to close the connection.While cases 1-3 can be handled automatically by underlying mechanisms (including cloned
Response
streams), scenario 4 requires manual handling. As noted in #13950, Sentry’sfetch
implementation cannot detect when streams are canceled viacancel()
, particularly in libraries likeflv.js
, leading to long-lived connections that don't close.Proposed Solution
To resolve this, I overrode the
cancel
method in theResponse
body to ensure that connections are properly terminated when the original response is canceled. Below is a modified implementation ofresolveResponse
:Replay Integration Issue
While implementing this fix, I also noticed that enabling the
replayIntegration
option causes the same issue where connections cannot be closed. I traced the problem to the_tryGetResponseText
function inpackages/replay-internal/src/coreHandlers/util/fetchUtils.ts
. This function usesresponse.text()
to fetch response data with a 500ms timeout, but this call fails to detect the use ofcancel()
.I also referenced the
response.text()
implementation in Node.js (unfortunately, I was only able to find the Node.js implementation, but I believe the behavior should be similar in the browser environment). In Node.js,response.text()
ultimately callsreadAllBytes
to retrieve the data, as shown below:This implementation does not account for the 500ms timeout that we set, resulting in
readAllBytes
never exiting. Therefore, I modified the_tryGetResponseText
implementation to manage theResponse
stream directly, as follows:Expected Result
Application can correctly exit connections for long-lived streams
Actual Result
The connection does not exit as expected.
Conclusion
With the modifications above, my application no longer experiences the issue of long-lived connections that cannot be closed. I would appreciate it if you could review this solution and provide any feedback for further improvement. Thank you!
The text was updated successfully, but these errors were encountered: