fix: propagate client disconnects to response body streams#93906
fix: propagate client disconnects to response body streams#93906coffeeispower wants to merge 2 commits into
Conversation
|
@coffeeispower i faced the same issue. Just stumbled on an upstream fix in recent nodejs 24.16 do you think your fix would compete in an unexpected way with the one of node ? |
|
@belgattitude I'm not running next.js on node.js, i'm running it on bun.js because I actually depend on some of its libraries like postgres and redis and Bun.file, Bun.exec and other functions, but i still was able to reproduce it in node.js too so I thought it was a next.js bug |
|
But either way, it's better to be safe than sorry, if it double-closes the stream it will throw an exception but I already made it ignore the exception because it's not really useful and doesn't affect anything |
|
Make sense. Thanks for clarification. I’ll link this PR #93938 to keep visibility as I’m interested by a resolution to this exact issue |
What?
Fixes response stream cancellation when the client disconnects before the response body finishes streaming.
Why?
Long-lived streaming responses need their body stream to be cancelled when the client connection is closed. Without that cancellation, application cleanup logic attached to the stream may not run, which can leave per-client resources alive after the client has gone away even if the app has registered a event listener using
request.signal.addEventListener("abort", ...)This was found while building Radiant, a TypeScript web app for creating radios that you can schedule playlists, songs, ad sections and other things and it serves long-lived ICY/audio streams from Next.js route handlers. Each listener connection owns stream resources and registers cleanup logic that must run when the client disconnects.
In the real reproduction case, connecting with
mpvand then closing the player aborted the HTTP response, but the response body stream was not cancelled. The route returned, but the stream finalizer responsible for removing the listener from the radio runtime did not run until this piping path was patched to propagate the disconnect to the body stream.This is not only specific to audio: the same issue can affect any long-lived response body stream that relies on cancellation/finalizers for cleanup, such as event streams, proxy streams, or custom streaming route handlers.
How?
The response piping path now propagates client aborts to the response body stream. It also avoids surfacing noisy double-close errors when the writable side has already been closed or errored during disconnect cleanup.