-
Notifications
You must be signed in to change notification settings - Fork 27k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Api route req on close event not triggered when request is cancelled #52809
Comments
perhaps related #52281 |
I also just noticed that |
So, this is working as intended. |
@jridgewell I see. Thx for the explanation. However, not even |
Also, if I disable bodyParser, the request |
Strange, I'm not sure why the close event isn't firing. |
Ok, now I see what's happening. We're using an async iterator with a break condition: next.js/packages/next/src/server/next-server.ts Lines 1537 to 1538 in 87763d7
The loop's body only runs after data has been received (you write something in your API response), where we can check if the client has disconnected and break. The I'll update so that we listen for the close signal outside of the loop as well. |
not sure if I am doing something wrong, but in the linked sandbox I still don't see |
When invoking the response piping in the Node server, special attention should be paid to the issue of backpressure. I highly recommend using the node Readable.from(iterable) method to obtain the readable stream, and then using the node stream.pipe method to pipe the readable stream to the outgoing stream. If this occurs on the edge, simply employ the approach utilized in the This will also provide support for user abortion since the pipe function listens for the underlying response close event and will handle any error issues appropriately. |
### What? This reimplements our stream cancellation code for a few more cases: 1. Adds support in all stream-returning APIs 2. Fixes cancellation detection in node 16 3. Implements out-of-band detection, so can cancel in the middle of a read It also (finally) adds tests for all the cases I'm aware of. ### Why? To allow disconnecting from an AI service when a client disconnects. $$$ ### How? 1. Reuses a single pipe function in all paths to push data from the dev's `ReadableStream` into our `ServerResponse` 2. Uses `ServerResponse` to detect disconnect, instead of the `IncomingMessage` (request) - The `close` event fire once all incoming body data is read - The request `abort` event will not fire after the incoming body data has been fully read 3. Using `on('close')` on the writable destination allows us to detect close - Checking for `res.destroyed` in the body of the loop meant we had to wait for the `await stream.read()` to complete before we could possibly cancel the stream - - - #52157 (and #51594) had an issue with Node 16, because I was using `res.closed` to detect when the server response was closed by the client disconnecting. But, `closed` wasn't [added](nodejs/node#45672) until [v18.13.0](https://nodejs.org/en/blog/release/v18.13.0#:~:text=%5Bcbd710bbf4%5D%20%2D%20http%3A%20make%20OutgoingMessage%20more%20streamlike%20(Robert%20Nagy)%20%2345672). This fixes it by using `res.destroyed`. Reverts #52277 Relands #52157 Fixes #52809 ---------
### What? This reimplements our stream cancellation code for a few more cases: 1. Adds support in all stream-returning APIs 2. Fixes cancellation detection in node 16 3. Implements out-of-band detection, so can cancel in the middle of a read It also (finally) adds tests for all the cases I'm aware of. ### Why? To allow disconnecting from an AI service when a client disconnects. $$$ ### How? 1. Reuses a single pipe function in all paths to push data from the dev's `ReadableStream` into our `ServerResponse` 2. Uses `ServerResponse` to detect disconnect, instead of the `IncomingMessage` (request) - The `close` event fire once all incoming body data is read - The request `abort` event will not fire after the incoming body data has been fully read 3. Using `on('close')` on the writable destination allows us to detect close - Checking for `res.destroyed` in the body of the loop meant we had to wait for the `await stream.read()` to complete before we could possibly cancel the stream - - - vercel#52157 (and vercel#51594) had an issue with Node 16, because I was using `res.closed` to detect when the server response was closed by the client disconnecting. But, `closed` wasn't [added](nodejs/node#45672) until [v18.13.0](https://nodejs.org/en/blog/release/v18.13.0#:~:text=%5Bcbd710bbf4%5D%20%2D%20http%3A%20make%20OutgoingMessage%20more%20streamlike%20(Robert%20Nagy)%20%2345672). This fixes it by using `res.destroyed`. Reverts vercel#52277 Relands vercel#52157 Fixes vercel#52809 ---------
@ijjk @jridgewell I don't think the issue is fixed. I've updated my example to use 13.4.13 but I still see the same issue. Here is also the @jridgewell's updated version which also shows that it's not fixed |
This now works in dev, but we're still seeing it not working in standalone production builds. I'm digging into the cause but wanted to give a heads up. |
Given that this works in dev, I think it might be CodeSandbox's servers that are breaking it. Even an app route handler doesn't work.
Are you deploying to Vercel? It was pointed out to me yesterday that we don't support streaming Pages API when running the nodejs runtime. I'm trying to bring this up to the team, and I'll see if we can fix that. |
We're using a standalone NodeJS build that we deploy to GCP cloud run, and we're on app, not pages. If you think that should work I can try to make a minimal repro. |
This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you. |
Verify canary release
Provide environment information
Operating System: Platform: linux Arch: x64 Version: #22 SMP Tue Jan 10 18:39:00 UTC 2023 Binaries: Node: 18.14.2 npm: 9.5.0 Yarn: 1.22.19 pnpm: N/A Relevant Packages: next: 13.4.10-canary.8 eslint-config-next: 13.4.8 react: 18.2.0 react-dom: 18.2.0 typescript: 5.0.4 Next.js Config: output: N/A
Which area(s) of Next.js are affected? (leave empty if unsure)
Middleware / Edge (API routes, runtime)
Link to the code that reproduces this issue or a replay of the bug
https://codesandbox.io/p/sandbox/blissful-driscoll-y78mrd
To Reproduce
req.on("close"
event handler didn't run and API route work is still being doneDescribe the Bug
Request close event is not firing in the API route when the caller cancels the request
Expected Behavior
Request close event should be fired so that any necessary cleanup can be done
Which browser are you using? (if relevant)
No response
How are you deploying your application? (if relevant)
No response
The text was updated successfully, but these errors were encountered: