我有一个节点应用程序,它运行长时间运行的任务,所以每当一个任务运行时,就会派生一个子进程来运行该任务。代码为要运行的任务创建一个fork,并向子进程发送一条消息以启动。
最初,当任务完成时,我向父进程发送一条消息,父进程将对子进程调用.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();
});
})
3条答案
按热度按时间ddhy6vgd1#
kill
向子进程发送信号。在没有参数的情况下,它发送一个SIGTERM
(其中TERM
是“termination”的缩写),顾名思义,它通常会终止进程。然而,发送这样的信号是停止进程的强制方法。如果进程正在执行写入文件等任务,并且收到终止信号,则可能会导致文件损坏,因为进程没有机会将所有数据写入文件并关闭它(对此有缓解措施,比如安装一个信号处理程序,可以用来“捕获”信号并忽略它们,或者在退出之前完成所有任务但这需要将显式代码添加到子进程)。
而在
process.exit()
中,进程 * 自身 * 退出。通常,它在知道没有更多的挂起任务时这样做,因此它可以干净地退出。一般来说,这是停止(子)进程的最佳方式。至于为什么这些进程没有被删除,我不确定。可能父进程没有清理子进程的资源,但我希望这会自动发生(我甚至不认为你可以在Node.js中显式地执行所谓的“子进程收割”)。
jdgnovmf2#
调用
process.exit(0)
是最好的机制,尽管在某些情况下,您可能希望从父级调用.kill
(例如,.kill
)。分布式搜索,其中一个节点返回意味着所有节点可以停止)。.kill
可能是由于对它接收到的信号进行了一些处理而失败的。尝试.kill('SIGTERM')
,甚至是'SIGKILL'。还要注意,当父进程退出时没有被杀死的子进程将被移动到祖父进程。有关更多信息和建议的解决方案,请参见此处:https://github.com/nodejs/node/issues/13538
总之,这是默认的Unix行为,解决方法是
process.on("exit", () => child.kill())
slhcrj9b3#
对我来说,杀死
.exec()
子进程唯一有效的方法是在尝试使用kill的每一个信号都不起作用后使用npm库terminate
。但是terminate
做到了。具体操作如下:其中
myProcess
简单地是:const myProcess = childProcess.exec(...)
。您不需要在子进程上使用{ detached: true }
,这不是必要的。您可以使用以下命令安装terminate:
yarn add terminate
这一招非常有效。