-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Close adapter-node server gracefully on SIGINT and SIGTERM #9540
Comments
As pointed out in the docs, such shutdown logic is highly dependent on the environment you're running in. Even if we would add the code you proposed, it would only work for some of the people because
Therefore closing. |
I'm going to reopen this issue. We now require Node 18, so that's no longer an issue. Also, I think it's fine to have environment-specific logic as that's the point of adapters. Rich currently has a PR out for reading files which introduces a concept of an adapter specifying what features are supported on a platform. We could use such a concept here if needed I used to work at Google and on each deploy, we'd take instances out of the load balancer, wait for all requests to drain, and then shut down the instance before deploying the new instance. It seems like a really important feature to me |
Agreed; graceful shutdown is table stakes. In python and ruby it's a given that the web server waits for requests to terminate before shutting down. Related project, that is be used by nuxt/nitro: https://github.com/sebhildebrandt/http-graceful-shutdown#explanation The readme has quite a nice visualization. |
What do you mean by this? Does Node 18 handle a server shutdown differently? We use Node 18 also, and use this snippet in a import { server } from '../build/index.js';
process.on('SIGINT', () => {
console.log('Got SIGINT. Starting graceful shutdown.');
shutdownServer();
});
process.on('SIGTERM', () => {
console.log('Got SIGTERM. Starting graceful shutdown.');
shutdownServer();
});
function shutdownServer() {
server.server?.close(() => {
console.log('Server closed');
process.exit(0);
});
server.server?.closeIdleConnections();
setInterval(() => server.server?.closeIdleConnections(), 1_000);
setTimeout(() => server.server?.closeAllConnections(), 20_000);
} |
@vekunz The minimu version required by SvelteKit is Node.js 18 today so if we implement this feature we wouldn't have to check if Could you explain a bit more why you call |
server.server?.closeIdleConnections();
setInterval(() => server.server?.closeIdleConnections(), 1_000); This code is there, because setTimeout(() => server.server?.closeAllConnections(), 20_000); This is a fallback, if there are connections that "don't want" to go idle. |
Ah I just realized you also call |
I did some more research and want to share my results. Many libraries still support Node.js 16 which is why it's difficult to find a recent example of how to gracefully shutdown the Node HTTP server. What those that still use Node.js v16 do, is track the requests and connections, call import http from 'node:http';
const port = process.env.PORT ?? 3000;
const shutdown_timeout = parseInt(process.env.SHUTDOWN_TIMEOUT) || 30;
let requests = 0;
let shutdown_timeout_id;
function shutdown() {
if (shutdown_timeout_id) return;
server.closeIdleConnections();
server.close(() => clearTimeout(shutdown_timeout_id));
shutdown_timeout_id = setTimeout(() => server.closeAllConnections(), shutdown_timeout * 1000);
}
const server = http.createServer(async (req, res) => {
res.writeHead(200).end();
});
server.on('request', (req) => {
requests++;
req.on('close', () => {
requests--;
if (shutdown_timeout_id) {
server.closeIdleConnections();
}
});
});
server.listen({ port }, () => console.log(`Listening on ${port}`));
process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);
This is essentially what everyone else does too and it works as expected in my tests. Because |
OK - sad news So I was having trouble closing down a project built using node-adapter. It took me a while but I found out that it's because it has a MongoDb connection. When I removed it - it would shut down properly.
I found that even if I manually set the shutdown_timeout to 1 - nothing would happen and it would just sit there. Obviously annoying when deploying ! Perhaps there's a way to tell the Mongo Adapter to shutdown ? But it seems bad to force the user to always shutdown gracefully IMHO. Node 20 here ... |
This is expected.
You need to clean up your resources — either by using a
Before |
Hm yes that makes a lot of sense in production in particular. |
So now I did the following:
This works if I run node build/index.js. But now I can't Ctrl+C out of 'npm run dev' ! It's somehow reversed it! |
FWIW it's easy enough to conditionally bind dependent on some ENV variable that's set in the package.json dev script, but it's a bit fiddly. |
So need a bit of best practice advice.... I have a Sveltekit project that uses a mongo server using adapter-node I need to add the following to make the project exit when I Ctrl+C.
But then in
But this doesn't feel like a great way to do it . Can anyone suggest best practice here ? |
Adapters don't run in development, only in production. The code is correct although I would set the timeout equal to |
I'm looking into whether we can add a simple hook to make this easier. |
Nice ! Something like that would be good - appreciate there's a lot get it all working smoothly . RN it doesn't feel like a great DX for what should be a very common use case of connecting to a database in production. |
@weepy the hook has just been added to process.on('sveltekit:shutdown', reason => {
db.close();
} |
Describe the problem
Currently, when building a SvelteKit app with the adapter-node, the production build does not handle SIGINT or SIGTERM signals. The result of this is that the SvelteKit app cannot be gracefully stopped, e.g. in a dockerized environment (Kubernetes in our case). The environment has to kill the app in order to shut it down. In a continuous deployment scenario this results in many broken HTTP requests.
Describe the proposed solution
Since this is a problem for anyone using the node adapter, this should be "fixed" generally in adapter-node.
The
index.js
file of adapter-node can be extended with this snippet (and the same for SIGTERM also):Alternatives considered
Alternatively, anyone has to build the same custom logic for this.
Importance
would make my life easier
Additional Information
If the SvelteKit team says that such logic should be implemented in adapter-node, I can create a Pull Request for this (actually I already wrote the code for this in a fork and just need to create the Pull Request for it, but I wanted to ask first).
The text was updated successfully, but these errors were encountered: