next.js
4055dd0c - feat(after): wait for after-callbacks before server shutdown (#72590)

Commit
1 year ago
feat(after): wait for after-callbacks before server shutdown (#72590) ### What This PR improves the reliability of `unstable_after` in a self-hosted context, i.e. on a long-running server (`next start`). when the server receives a signal to gracefully shutdown, we'll wait for any operations scheduled with `unstable_after` to finish, and then exit. ### Why It's less surprising than dropping pending operations on the floor if an instance is getting shut down. This mirrors the standard behavior of finishing handling pending requests before exiting -- we're just extending this a bit to include `after` tasks. ### How Previously `waitUntil` was just a noop in `next start`, so passing a promise to it did nothing. This PR changes the implementation to instead use an "awaiter" that stores promises passed to it and lets us wait for all of them to complete. We then use some existing `onCleanup` machinery to make sure that they're actually awaited before shutdown. Note that I've now made `NextServer.close()` execute before shutdown. This is notable because AFAICT this wasn't being called anywhere before, which is a bit suspicious. ### How (in a bit more detail) This is all a bit hard to follow so here's an overview of how it works: - We have two entrypoints: `startServer` and `NextCustomServer` - `startServer`: - creates a cleanup set (`AsyncCallbackSet`) - calls `createRequestHandlers`, which... - passes `onDevServerCleanup` to turbopack's hot reloader (previously `onCleanup`) - creates a `NextServer` - which will create a `NextNodeServer` - which sets up an `Awaiter` to ensure all `after` callbacks finished running. - adds a call to `NextServer.close()` to the cleanup set - when we receive SIGINT/SIGTERM, we run `NextServer.close()`, which runs `NextNodeServer.close()`, which waits for pending `after` callbacks to finish using the Awaiter. - `NextCustomServer`: - does basically the same setup with a cleanup set and `createRequestHandlers` - but it does not set up a SIGINT/SIGTERM handler to run the cleanups. instead, it expects the user to call its `cleanup()` method when appropriate (basically like we do in `startServer`) - i'm gonna do a follow up and update the custom server docs to reflect this - also going to try to warn if a cleanup was needed but the process exited without it calling it
Author
Parents
Loading