我有一个节点后端,它使用express接收HTTP请求。我像这样优雅地关闭:
process.on( 'SIGINT', function() {
console.log("SIGINT signal received.");
server.close(function(err) {
if (err) {
console.error(err)
process.exit(1)
}
//Stop reoccurring tasks
//Close database connection
process.exit(0);
});
process.exit(0);
});我的工作很好,但我关心的是我的“停止重复任务”的步骤。在我的代码的其他地方,我调用了一个如下所示的函数:
export async function launchSectionFinalizer() {
finalizeSections();
//1 hr * 60 min/hr * 60 s/min * 1,000 ms/s = 3,600,000 ms
return setInterval(finalizeSections, 3_6000_000);
}其中finalizeSections是一个异步函数,它执行一系列数据库操作(postgres数据库)。
我的问题是关于setInterval的性质和行为。当我收到SIGINT时,如何确保finalizeSections不处于其执行过程中?我担心如果我的程序接收到SIGINT并在错误的时间关闭服务器,它可能会在其操作过程中捕获finalizeSections。如果发生这种情况,我可能会部分完成这些数据库操作(即,如果我一个接一个地执行一系列insert1、insert2和insert3命令,我不希望在没有执行3的情况下执行1和2)。
我已经做了一些谷歌,并阅读了一些关于节点将如何等待它的所有进程和事件完成,然后才关闭。这包括等待我对finalizeSections的调用完成吗?
另外,我知道clearInterval,但我不确定该函数是否只停止计时器,或者它是否也会导致节点等待finalizeSections完成。
发布于 2022-03-15 07:04:53
调用clearInterval只会取消计时器,而不会等待finalizeSections完成。
由于您优雅的关机调用了process.exit(0),所以它不会等待挂起的异步任务完成,它将立即退出:
调用process.exit()将迫使进程尽快退出,即使仍有尚未完全完成的异步操作,包括对process.stdout和process.stderr的I/O操作。
不使用任何包解决此问题的一种方法是保存对finalizeSections()返回的承诺和setInterval()返回的intervalId的引用。
intervalId = setInterval(() => {
finalizeSectionsPromise = finalizeSections();
}, 3_6000_000)然后在关机密码里。
clearInterval(intervalId);
if (finalizeSectionsPromise) {
await finalizeSectionsPromise;
}
...
process.exit(0);如果您能够使用其他包,我将使用作业调度库,如Agenda或Bull,甚至cron作业:
https://github.com/OptimalBits/bull
https://github.com/agenda/agenda
还可以查看一个可停止或终止的服务器,以便在不杀死正在运行的请求的情况下优雅地关闭服务器:
https://stackoverflow.com/questions/71477445
复制相似问题