检测父进程何时退出

10
我将有一个父进程用于处理 web 服务器重启。它会向子进程发出停止监听新请求的信号,子进程会向父进程发出停止监听的信号,然后父进程会向新子进程发出可以开始监听的信号。这样,我们可以在不到100毫秒的时间内完成该级别的重启(我还有一个零停机的孙子级别的重启,但这并不总是足够的)。
当服务管理器决定关闭时,它会杀死父进程。子进程如何检测父进程已经结束?
这些信号是通过子进程的标准输入和标准输出发送的。也许我可以检测 stdin 流的结束?我希望避免轮询间隔。此外,如果可能的话,我希望这是一种真正快速的检测方法。
4个回答

18

一个更简单的解决方案可能是在子进程中注册 'disconnect'。

process.on('disconnect', function() {
  console.log('parent exited')
  process.exit();
});

谢谢!我尝试了所有方法,这似乎是唯一能够捕获到您的父进程被 -9 终止的方式。 - Abdullah Jibaly
我非常同意这是个好的解决方案。在我的情况下,我正在监听来自父进程的SIGTERM事件以及(如果发生任何不良事件并且我需要重新启动父进程)断开事件。对于我的情况,问题是明显的,因为子进程创建了占用端口的服务器,因此再次启动会导致“ERRADDRINUSE”。这解决了问题:) - JakubKnejzlik

8

以下是一个示例,展示了entropo提出的node-ffi解决方案(如上所述,它将在Linux上运行):

这是父进程,它会生成子进程,然后在5秒后退出:

var spawn = require('child_process').spawn;
var node = spawn('node', [__dirname + '/child.js']);
setTimeout(function(){process.exit(0)}, 5000);

这是子进程(位于child.js中)

var FFI = require('node-ffi');
var current = new FFI.Library(null, {"prctl": ["int32", ["int32", "uint32"]]})

//1: PR_SET_PDEATHSIG, 15: SIGTERM
var returned = current.prctl(1,15);

process.on('SIGTERM',function(){
        //do something interesting
        process.exit(1);
});

doNotExit = function (){
        return true;
};
setInterval(doNotExit, 500);

如果没有当前的.prctl(1,15),即使父进程正在退出,子进程也会一直运行下去。在这里,它将被使用SIGTERM信号通知,并得到优雅处理。


对于实现此解决方案的人,请在确实完成之前不要调用 process.exit(1)。logger.warn("SIGTERM. 正在平稳退出。", function() {process.exit(1);}) - itaifrenkel
看起来 node-ffi 已经被新模块 "ffi" 取代了。 - mpr

5

我认为这会奏效。当关闭时间到来时,父进程被终止,但我非常确定退出监听器仍然有效。也许我仍然可以每隔几秒钟检查一次父进程ID,如果它变成数字1,那就意味着父进程已经死亡。 - 700 Software
3
如果您正在关闭,您的进程将首先收到 SIGTERM 信号。您可以通过以下方式捕获并进行清理:process.on('SIGTERM', function () { console.log('收到 SIGTERM 信号,正在退出...'); // 在这里进行一些清理操作... process.exit(0); }); - entropo
1
是的,让子进程定期检查其 PPID 是否变为 1 是一种很好的备选方案,适用于父进程没有正常退出的情况。参见:https://dev59.com/EnVC5IYBdhLWcg3whBej - entropo

2

我在本地的OSX应用程序中作为后台工作者启动Node.JS。为了使node.js在消费node.js标准输出的父进程死亡/退出时退出,我执行以下操作:

// Watch parent exit when it dies

process.stdout.resume();
process.stdout.on('end', function() {
  process.exit();
});

就这么简单,但我不确定这是否是你所询问的内容;-)


我曾经为这个用例苦苦挣扎,但现在它完美地运行了。干杯! - sak
process.stdout.resume() 对我来说崩溃了。 - Nathan Goings
看起来这是一个旧的用法。移除resume()开始工作。另外,事实证明我正在寻找的事件是error - Nathan Goings

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接