我在一个运行npm start
的Nodejs应用程序中遇到了一个问题(只是node app.js
)。
我的应用程序包含一个sigint处理程序,如下所示:
process.on('SIGINT', () => {
db.disconnect().then({
process.exit(0);
}).catch(e => process.exit(1));
});
带有相应的日志。在对其他文件进行一些测试之后,我注意到在npm
进程上进行Ctrl-C触发时,如果第一个退出退出的时间太长,则会两次触发SIGINT。 (尝试在示例应用程序上添加超时)。
现在,我添加了一个计数器来检查是否多次执行了呼叫,但是我不确定这是否是解决此问题的“方法”。我猜想npm进程上的SIGINT会在某个时间范围内退出,这就是为什么npm再过一次(总是只有两次)通过它的原因。
有人遇到这个问题并找到了可行的解决方案吗?
谢谢!
答案 0 :(得分:3)
您可能想直接通过节点而不是通过npm start
运行命令。 NPM可能会导致信号陷入更复杂的陷阱,请参见https://lisk.io/blog/tutorial/why-we-stopped-using-npm-start-child-processes。
您的SIGINT处理程序可以多次调用,您应该编写代码来防止这种情况。
如果您正在运行父/子进程,请参见https://github.com/jtlapp/node-cleanup
按Ctrl-C组合键时,您会向SIGINT中的每个进程发送一个SIGINT信号。 当前的流程组。流程组是以下流程的集合: 所有这些都应该作为一个群体而结束而不是坚持下去 独立地。但是,某些程序(例如Emacs)会拦截并 重新调整SIGINT的用途,以便它不会结束该过程。在这种情况下 SIGINT不应结束该组的任何进程。
此外,在大多数时候不需要调用process.exit,请参见https://nodejs.org/api/process.html#process_process_exit_code
改为设置process.exitCode
,删除信号处理程序,然后通过process.kill(process.pid, signal)
重新引发信号
答案 1 :(得分:2)
我知道这篇文章已经存在了一段时间,但不幸的是我遇到了同样的问题。仅运行node <app.js>
时,它仅触发一个信号。如果运行npm start
,则该信号出现两次。
我建议检查服务器是否仍在侦听,而不是一个计数器,如果是,请继续执行逻辑和内部终止(例如db连接等):
process.on('SIGINT', function(){
if (server.listening) {
server.close(function (err) {
if (err) {
console.error(err);
process.exit(1)
}
process.exit(0);
})
}
})
答案 2 :(得分:0)
假设以下代码位于名为 x.js 的文件中。
假设您在package.json文件中有一个名为 start 的npm脚本,该脚本执行 node x.js 命令。
process.on("SIGINT", (signal) => {
console.log(signal + " signal received.");
process.exitCode = 0;
});
setTimeout(function() {
console.log("Hello");
}, 5000);
如果我们使用命令node x.js
运行代码,则该代码将仅打印1行“收到的SIGINT信号”。但是,如果我们使用命令npm run start
运行代码,则该代码将打印两行“收到的SIGINT信号”。除此之外,如果我们使用npm软件包nodemon
来监视我们的代码,并且使用命令nodemon x.js
运行该代码,该代码还将打印两行“收到的SIGINT信号”。 / p>
如果我们使用process.exit(0);
而不是process.exitCode = 0;
,我们会发现由于强制退出进程,上述所有命令仅会打印1行“收到SIGINT信号”。
如果我们不直接调用node
命令并且在这种情况下使用诸如npm
和nodemon
之类的层来触发node
命令,则会导致这种解释该层两次将SIGINT信号传递到节点进程。
环境:
macOS Mojave v10.14.6
npm v6.10.0
节点v12.7.0
nodemon v1.18.11
答案 3 :(得分:0)
一个更简洁的解决方案是将断开连接的处理程序包装在一个 promise 中,并且由于 promise 内部实现,resolve 将仅被调用一次。
new Promise((resolve) => process.on('SIGINT', resolve))
.then(() => db.disconnect())
.then(() => process.exit(0))
.catch(() => process.exit(1));
注意:我建议避免显式调用 process.exit() 并让节点自行退出。如果由于某些原因该进程没有退出,则意味着有什么东西阻止了它(例如:端口侦听、打开/挂起的 tcp 连接、未清除的 setInterval
或 setTimeout
引用)