NodeJs "graceful shutdown" 应该如何处理 setInterval?
How should a NodeJs "graceful shutdown" handle setInterval?
我有一个节点后端使用 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,我不想执行 1 和 2 也没有执行 3).
我进行了一些谷歌搜索并阅读了一些有关节点如何在关闭之前等待其所有进程和事件完成的内容。这是否包括等待我对 finalizeSections 的调用完成?
此外,我知道 clearInterval,但我不确定该函数是否只会停止计时器,或者它是否还会导致节点等待 finalizeSections 完成。
调用clearInterval只会取消定时器,不会等待finalizeSections完成。
因为您的正常关机调用 process.exit(0)
它不会等待挂起的异步任务完成,它会立即退出:
Calling process.exit() will force the process to exit as quickly as possible even if there are still asynchronous operations pending that have not yet completed fully, including I/O operations to process.stdout and process.stderr
在不使用任何包的情况下解决这个问题的一种方法是保存对 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
另请查看 stoppable 或 terminus 以优雅地关闭服务器而不杀死 in-flight:
的请求
https://www.npmjs.com/package/stoppable
https://github.com/godaddy/terminus
我有一个节点后端使用 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,我不想执行 1 和 2 也没有执行 3).
我进行了一些谷歌搜索并阅读了一些有关节点如何在关闭之前等待其所有进程和事件完成的内容。这是否包括等待我对 finalizeSections 的调用完成?
此外,我知道 clearInterval,但我不确定该函数是否只会停止计时器,或者它是否还会导致节点等待 finalizeSections 完成。
调用clearInterval只会取消定时器,不会等待finalizeSections完成。
因为您的正常关机调用 process.exit(0)
它不会等待挂起的异步任务完成,它会立即退出:
Calling process.exit() will force the process to exit as quickly as possible even if there are still asynchronous operations pending that have not yet completed fully, including I/O operations to process.stdout and process.stderr
在不使用任何包的情况下解决这个问题的一种方法是保存对 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
另请查看 stoppable 或 terminus 以优雅地关闭服务器而不杀死 in-flight:
的请求
https://www.npmjs.com/package/stoppable
https://github.com/godaddy/terminus