我有一个使用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。如果发生这种情况,我可能会部分完成这些数据库操作(即,如果我一个接一个地执行一系列sql命令,insert1、insert2和insert3,我不想在不执行3的情况下执行1和2(。
我已经在谷歌上搜索了一些关于节点如何在关闭之前等待所有进程和事件完成的内容。这会包括等待我对finalizeSections的调用完成吗?
此外,我知道clearInterval,但我不确定该函数是否只停止计时器,或者它是否也会导致节点等待finalizeSections完成。
调用clearInterval只会取消计时器,而不会等待finalizeSections完成。
因为您的优雅关闭调用process.exit(0)
,它不会等待挂起的异步任务完成,并且会立即退出:
调用process.exit((将强制进程尽快退出,即使仍有异步操作挂起,尚未完全完成,包括对process.stdout和process.stderr 的I/O操作
在不使用任何包的情况下解决此问题的一种方法是保存对finalizeSections()
返回的promise和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://www.npmjs.com/package/stoppable
https://github.com/godaddy/terminus