Node.js-process.exit()与childProcess.kill()

时间:2018-11-12 20:26:07

标签: node.js fork child-process

我有一个运行长时间运行任务的节点应用程序,因此每当任务运行一个子进程时,便会派生一个分支来运行任务。该代码为要运行的任务创建了一个分叉,并将消息发送到子进程以启动。

最初,当任务完成时,我正在将消息发送回父进程,并且父进程将在子进程上调用.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();
    });
})

2 个答案:

答案 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())