Graceful Shutdown
Unanswered
Artois Hound posted this in #help-forum
Artois HoundOP
The one in the docs won't work for me since I have a different system, but I have something similar:
The log is logged and the server is killed, however, the requests are cancelled mid-run and aren't finished. Anyone has an idea how to ensure that all the API requests are finished before the server is shut down? I am also using MongoDB, but I figured that if the API finishes, there won't be anything going on with the DB anyway. The goal is to ensure that no new requests are accepted and that the ongoing requests are finished entirely before shutting down.
const nextDevProcess = exec('next dev');
process.on('SIGINT', () => {
console.log('SIGINT received, shutting the server down...');
if (nextDevProcess) {
nextDevProcess.kill('SIGTERM');
}
process.exit();
});The log is logged and the server is killed, however, the requests are cancelled mid-run and aren't finished. Anyone has an idea how to ensure that all the API requests are finished before the server is shut down? I am also using MongoDB, but I figured that if the API finishes, there won't be anything going on with the DB anyway. The goal is to ensure that no new requests are accepted and that the ongoing requests are finished entirely before shutting down.
133 Replies
Artois HoundOP
I will head to sleep now, but if anyone has ideas for this, I will check tomorrow.
You shouldn't need to manually manage processes with next - also, why are you running
next dev from within code?@Marchy https://nextjs.org/docs/pages/building-your-application/deploying#manual-graceful-shutdowns
Artois HoundOP
Yes, I have read that, and it does not answer my questions anyway.
@Marchy You shouldn't need to manually manage processes with next - also, why are you running `next dev` from within code?
Artois HoundOP
I do need to, because I have npm run dev set to run the Next.js itself + some other scripts to save time on each start
@Marchy You shouldn't need to manually manage processes with next - also, why are you running `next dev` from within code?
Artois HoundOP
And I wouldn't have to manually manage it, but by default after I do CTRL+C the sever just shuts down whilst the API requests are still not finished, which could cause very large issues.
@Artois Hound I do need to, because I have npm run dev set to run the Next.js itself + some other scripts to save time on each start
You can run multiple scripts from your package.json with something like
next build && next start@Marchy why would that cause very large issues <:frynotsure:331533132295700495>
Artois HoundOP
Simple, imagine a user is withdrawing 1000$ from their account, the money is being sent to them but the API for deleting that money from their account in the DB hasn't been requested yet, and in the middle of it the server shuts down. Now the user has 1000$ in their bank bcs the request for the money went through, but the API request was never called. (it would require crazy timing, but it still could happen, more users, more likely)
@Marchy You can run multiple scripts from your package.json with something like `next build && next start`
Artois HoundOP
It's not so simple, I tried that, but I have some very special requirements
@Marchy You can run multiple scripts from your package.json with something like `next build && next start`
Artois HoundOP
It's been a while since I worked on that specific part, but I even had a fellow programmer help me with it, and we couldn't make this one work, so I had to build it extra
I am just kinda surprised there isn't a system built-in for this in Next.js ngl
No matter how hard I searched, there is barely anything about shutdowns
for Next.js specifically
@Marchy why are you running in dev mode though?
Artois HoundOP
Just so I don't have to rebuild it for every test, but prod is the same
@Artois Hound Just so I don't have to rebuild it for every test, but prod is the same
You're running dev mode in prod? and starting from exec?
Artois HoundOP
no
dev mode is dev mode
prod is prod
and yeah I run with exec
But the system for starting everything is working correctly, no issues there
the way you handle this will be different for dev and prod
dev should not be an issue if it drops a connection.. it's expected to break in local dev
Artois HoundOP
Well it's not like production works much differently
it doesn't finish the request either
I test that initially
you're running next in server mode?
Artois HoundOP
wym?
are you hosting on vercel or amplify or something? Or in a container?
Artois HoundOP
currently just local testing but it will be a VPS later on
Next doesn't support manual signal handling in dev mode, I'd assume because it messes with hot reloading
@Marchy Next doesn't support manual signal handling in dev mode, I'd assume because it messes with hot reloading
Artois HoundOP
Actually, the signal is logged so ig it works
Good to know: Manual signal handling is not available in next dev.@Marchy Good to know: Manual signal handling is not available in next dev.
Artois HoundOP
Yes, I read that too, but again I tested both prod and dev
and neither does it correctly
if prod worked, I wouldn't care dev doesn't lol
I'd have to know how your other scripts are structured and what they're doing, it sounds like you're managing multiple services from your node scripts
Artois HoundOP
Well, it's kinda complex by this point but the basic idea is quite simple, I just need the next.js API to finish it's requests before finishing the process
I am sure I could somehow do it manually in every single API, but I am trying to come up with a more elegant solution
It sounds like you should be using docker compose instead of managing the processes within node
https://docs.docker.com/compose/
https://docs.docker.com/compose/
also 1000000x better for performance
Artois HoundOP
Most things can be made very easy by just using third-party apps, but that ruins the entire idea of having most of your stuff custom to avoid dependencies.
@Artois Hound Most things can be made very easy by just using third-party apps, but that ruins the entire idea of having most of your stuff custom to avoid dependencies.
that has nothing to do with process management and cloud deployments
Still need to organize processes
@Marchy that has nothing to do with process management and cloud deployments
Artois HoundOP
literally the first message on that site:
And I don't like Docker much since I had to use it with Kubernetes 🤮
@Marchy Still need to organize processes
Artois HoundOP
Exactly, which can be done manually for sure.
I mean a lot of people have smth like this
if (!process.env.NEXT_MANUAL_SIG_HANDLE) {
process.on('SIGTERM', () => process.exit(0))
process.on('SIGINT', () => process.exit(0))which is no different from what I have, but as far as I know, this goes on by default even without putting it in your code lol
@Artois Hound I mean a lot of people have smth like this if (!process.env.NEXT_MANUAL_SIG_HANDLE) {
process.on('SIGTERM', () => process.exit(0))
process.on('SIGINT', () => process.exit(0))
that's literally the documentation I sent to you. Ctl+C is the command to inturrupt output, it will not wait for connections to finish.
@Marchy that's literally the documentation I sent to you. Ctl+C is the command to inturrupt output, it will not wait for connections to finish.
Artois HoundOP
I know, and that probably works, I mean I am not quick enough to check lol
What does not work is let's say: I set smth in the API to have a timeout, and then close it right? (timeout to simulate the the fact that it wouldn't run yet cuz you can't be so quick with it manually), and it doesn't run after CTRL+C
I know that already established connections are finished, that's by default
My problem is that the entire API is not run
Let's say half of it gets run, the other half never does
I mean it's obviously about timing, cuz it isn't easily reproducible, but as I said once you get a lot of users in, it's eventually gonna happen
it does this out of the box
if you use a serverless host, which it's intended for, you don't have to worry about that at all
Artois HoundOP
I use a VPS
You're talking about something that happens on the OS level, next.js doesn't handle process management on its own.
Artois HoundOP
I mean when I think about it I would just somehow need to get the info "is api running"
and somehow disable new api calls
That's what docker is great for
Artois HoundOP
So then I disable the API, and finish the ones already running
or pm2
Artois HoundOP
pm2?
I haven't used it in a long time because kubernetes is way more reliable but
https://pm2.keymetrics.io/docs/usage/quick-start/
https://pm2.keymetrics.io/docs/usage/quick-start/
Artois HoundOP
oh but it is way more sexy than Kubernetes
I used Kubernetes for AI and never again thx
@Artois Hound oh but it is way more sexy than Kubernetes
You say that now 😅
there's reasons why I used to use it
there's reasons why I used to use it
Artois HoundOP
And there's a reason I never want to see Kubernetes again 🤣
Almost made me hate coding lol
pm2 sits on top of a single process in node and limites how much resoures you can use
deploying to vercel is 10000000000000000000000x easier and cheaper
Artois HoundOP
Yeah but I never got onto the serverless hype
ok maybe not much cheaper if you're getting like millions of requests but still
Artois HoundOP
VPS is way simpler to understand for me
🤣
Artois HoundOP
I mean the main thing is that I am not just running next.js right
If I was, it would be way simpler
you can just kick those out to fly.io microservices
Artois HoundOP
That's what I am talking about, one thing here, other thing there and next thing you know it looks like my desk with cables all over the place lol
And the only thing you really need that for now is webrtc or something
Artois HoundOP
With a VPS, you just plug it in, run npm run build, then npm run start and done
all works
@Artois Hound With a VPS, you just plug it in, run npm run build, then npm run start and done
with vercel it's just "git push"
Strongly encourage you to give it a try as it's intended before you knock it
Original message was deleted
oh god why are you manually managing a mongoose connection on the process level please just use prisma it will do all of this for you
@Marchy oh god why are you manually managing a mongoose connection on the process level please just use prisma it will do all of this for you
Artois HoundOP
Again you want me to do a million third-parties hell no
Artois HoundOP
This is how you get into hell
One thing, then the next, then another one
next thing you know you got 100 different apps and once they need updates, gl with that
I have tried them all. Every single one of them. Use prisma.
Artois HoundOP
I have heard of Prisma before
But I see no benefit
all works for me rn
Yet here you are 🙂
Artois HoundOP
Well, what I am trying to do is more of a plus than an absolute necessity
The necessities work
I'm serious, I've been down this route and I've been building node applications for 10 years
js for 20
please
just use prisma
Artois HoundOP
I have heard of Prisma, and if I didn't use MongoDB I would probably use it
but MongoDB is the simplest thing ever
boom json and done
it just manages the connections for you
Artois HoundOP
I know, but I have nothing to gain
+ orm
you have everything to gain
Artois HoundOP
MongoDB does connection pooling by default
alright have fun spending the rest of your life debugging then 

Artois HoundOP
I mean you throw it at me, but aren't willing to give me a good argument for it?
Maybe you should reconsider using it then 🤣
I'm not going to explain very basic software engineering principals to you. Have a great day 

Artois HoundOP
I think you just messed yourself in here, you don't even know why you're using it lol
Just because it's trendy.
@Marchy I'm not going to explain very basic software engineering principals to you. Have a great day <a:pikachu_wave:767742832671981618>
Artois HoundOP
very basic software engineering principle is to use as little dependencies as possible
@Marchy https://tenor.com/view/smg4-smg4skill-issue-skill-issue-smg4mario-smg4skill-gif-26104493
Chartreux
Can you guys took a moment look at my question ,thx 

@Artois Hound but MongoDB is the simplest thing ever
Chartreux
I'm full stack developer , I would say you are wrong MangoDB is very complicated and very hard to maintain when your application go large in the future .
@Chartreux I'm full stack developer , I would say you are wrong MangoDB is very complicated and very hard to maintain when your application go large in the future .
Artois HoundOP
Anything specific in mind? I have already tested migration and it can be done fairly easily.
@Artois Hound Anything specific in mind? I have already tested migration and it can be done fairly easily.
Chartreux
const express = require('express');
const app = express();
const mongoose = require('mongoose');
const { exec } = require('child_process');
// MongoDB connection
mongoose.connect('YOUR_MONGODB_URI', { useNewUrlParser: true, useUnifiedTopology: true });
const server = app.listen(3000, () => {
console.log('Server started on http://localhost:3000');
});
const nextDevProcess = exec('next dev');
let connections = [];
server.on('connection', connection => {
connections.push(connection);
connection.on('close', () => connections = connections.filter(curr => curr !== connection));
});
process.on('SIGINT', () => {
console.log('SIGINT received. Gracefully shutting down...');
server.close(() => {
console.log('Closed out remaining connections.');
if (nextDevProcess) {
nextDevProcess.kill('SIGTERM');
}
mongoose.connection.close(false, () => {
console.log('MongoDB connection closed.');
process.exit(0);
});
});
// If server shutdown doesn't finish in 10 seconds, force it
setTimeout(e => {
console.error('Forced shutdown due to timeout.');
process.exit(1);
}, 10000);
connections.forEach(curr => curr.end());
setTimeout(() => connections.forEach(curr => curr.destroy()), 5000);
});
why you just google and try , just like this
const app = express();
const mongoose = require('mongoose');
const { exec } = require('child_process');
// MongoDB connection
mongoose.connect('YOUR_MONGODB_URI', { useNewUrlParser: true, useUnifiedTopology: true });
const server = app.listen(3000, () => {
console.log('Server started on http://localhost:3000');
});
const nextDevProcess = exec('next dev');
let connections = [];
server.on('connection', connection => {
connections.push(connection);
connection.on('close', () => connections = connections.filter(curr => curr !== connection));
});
process.on('SIGINT', () => {
console.log('SIGINT received. Gracefully shutting down...');
server.close(() => {
console.log('Closed out remaining connections.');
if (nextDevProcess) {
nextDevProcess.kill('SIGTERM');
}
mongoose.connection.close(false, () => {
console.log('MongoDB connection closed.');
process.exit(0);
});
});
// If server shutdown doesn't finish in 10 seconds, force it
setTimeout(e => {
console.error('Forced shutdown due to timeout.');
process.exit(1);
}, 10000);
connections.forEach(curr => curr.end());
setTimeout(() => connections.forEach(curr => curr.destroy()), 5000);
});
why you just google and try , just like this
Chartreux
i think mango will not shutdown the connections directly, lots of library or DB will keep a state (similar term) , it will not close directly , instead it will wait for a while , then shutdown , because if after you query , then mango shut down the connection , it will be very slow , because every time you have new query , the mango need to recreate the connection, this is the slowest way , so lots of library reuse the statements instead of shut down ,.
