我有一个运行长时间运行任务的节点应用程序,因此每当任务运行一个子进程时,便会派生一个分支来运行任务。该代码为要运行的任务创建了一个分叉,并将消息发送到子进程以启动。
最初,当任务完成时,我正在将消息发送回父进程,并且父进程将在子进程上调用.kill()。我在活动监视器中注意到未删除节点进程。所有的子进程都徘徊。因此,完成任务后,我没有在父进程中发送消息并调用.kill(),而是在子进程代码中调用了process.exit()。
第二种方法似乎运行良好,并且我看到节点进程已从活动监视器中删除,但是我想知道这种方法是否存在我不知道的缺点。一种方法比另一种更好吗?两种方法有什么区别?
对于消息传递方法,我的代码看起来像这样。
//Parent process
const forked = fork('./app/jobs/onlineConcurrency.js');
forked.send({clientId: clientData.clientId,
schoolYear: schoolYear
});
forked.on("message", (msg) => {
console.log("message", msg);
forked.kill();
});
//child Process
process.on('message', (data) => {
console.log("Message recieved");
onlineConcurrencyJob(data.clientId, data.schoolYear, function() {
console.log("Killing process");
process.send("done");
});
})
退出时子进程的代码看起来像这样
//child Process
process.on('message', (data) => {
console.log("Message received");
onlineConcurrencyJob(data.clientId, data.schoolYear, function() {
console.log("Killing process");
process.exit();
});
})
答案 0 :(得分:2)
kill
向子进程发送信号。如果没有参数,它将发送一个SIGTERM
(其中TERM
是“终止”的缩写),顾名思义,通常会终止该过程。
但是,发送这样的信号是强制停止进程的方法。如果该进程正在执行诸如写入文件之类的任务,并且接收到终止信号,则可能会导致文件损坏,因为该进程没有机会将所有数据写入该文件并关闭该文件(对此有一些缓解措施) ,例如安装一个信号处理程序,该信号处理程序可用于“捕获”信号并忽略它们,或者在退出之前完成所有任务,但这需要在子进程中添加明确的代码。
在process.exit()
中,进程退出本身。通常,它在知道没有其他待处理任务的情况下这样做,因此可以干净地退出。一般来说,这是停止(子)进程的最佳方法。
至于为什么不删除这些进程,我不确定。可能是父进程没有清理子进程的资源,但我希望这会自动发生(我什至不认为您可以在Node.js中显式执行所谓的“子收割”)
答案 1 :(得分:0)
调用process.exit(0)
是最好的机制,尽管在某些情况下,您可能想从父级那里.kill
(例如,分布式搜索,其中一个节点返回意味着所有节点都可以停止)。>
.kill
可能由于处理收到的信号而失败。尝试.kill('SIGTERM')
甚至是“ SIGKILL”。
还请注意,在父流程退出时未被杀死的子流程将移至祖父母流程。有关更多信息和建议的解决方法,请参见此处:https://github.com/nodejs/node/issues/13538
总而言之,这是默认的Unix行为,解决方法是process.on("exit", () => child.kill())