gpt4 book ai didi

node.js - Node 子进程 : how to intercept signals like SIGINT

转载 作者:IT老高 更新时间:2023-10-28 23:25:20 25 4
gpt4 key购买 nike

在我的 Node 应用程序中,我挂上了 SIGINT 信号以便正常停止(使用 pm2,但这与此处无关)。

我的应用还执行/生成了几个子进程。

我能够挂上 SIGINT 来拦截它并执行正常停止,然而我的子进程通过相同的信号传递,因此被立即杀死。

如何拦截子进程上的 SIGINT 信号?

我正在做的一个示例:

const child = child_process.spawn('sleep', ['10000000']);
console.log(`Child pid: ${child.pid}`);

child.on('exit', (code, signal) => { console.log('Exit', code, signal); });

process.on('SIGINT', () => {
console.log("Intercepting SIGINT");
});

最佳答案

默认情况下,由 child_process.spawn() 创建的子进程具有相同的 process group作为父级,除非使用 {detached:true} option 调用它们.

结果是这个脚本在不同的环境中会有不同的表现:

// spawn-test.js
const { spawn } = require('child_process');
const one = spawn('sleep', ['101']);
const two = spawn('sleep', ['102'], {detached: true});
two.unref();
process.on('SIGINT', function () {
console.log('just ignore SIGINT');
});

在交互式 shell 上,默认情况下,来自 Ctl-C 的 SIGINT 会发送到整个组,因此未分离的 child 将获得 SIGINT 并退出:

you@bash $ node spawn-test.js
^Cjust ignore SIGINT
# the parent process continues here, let's check children in another window:
you@bash [another-terminal-window] $ ps aux | grep sleep
... sleep 102
# note that sleep 101 is not running anymore
# because it recieved the SIGINT from the Ctl-C on parent

...但是对 kill(2) 的调用只能向您的父进程发出信号,因此子进程可以存活:

you@bash $ node spawn-test.js & echo $?
[2] 1234
you@bash [another-terminal-window] $ kill -SIGINT 1234
you@bash [another-terminal-window] $ ps aux | grep sleep
... sleep 101
... sleep 102
# both are still running

然而,pm2 完全是另外一头野兽。即使您尝试上述技术,它也会杀死整个进程树,包括您的分离进程,即使是很长的 --kill-timeout:

# Test pm2 stop
you@bash $ pm2 start spawn-test.js --kill-timeout 3600
you@bash $ pm2 stop spawn-test
you@bash $ ps aux | grep sleep
# both are dead

# Test pm3 reload
you@bash $ pm2 start spawn-test.js --kill-timeout 3600
you@bash $ pm2 reload spawn-test
you@bash $ ps aux | grep sleep
# both have different PIDs and were therefore killed and restarted

这似乎是 pm2 中的一个错误。

我已经通过使用 init 系统(在我的例子中是 systemd)而不是 pm2 解决了类似的问题,因为这样可以更好地控制信号处理。

在 systemd 上,默认情况下将信号发送到整个组,但您可以使用 KillMode=mixed 将信号仅发送到父进程,但如果它们运行超出,仍会 SIGKILL 子进程超时。

我的 systemd 单元文件如下所示:

[Unit]
Description=node server with long-running children example

[Service]
Type=simple
Restart=always
RestartSec=30
TimeoutStopSec=3600
KillMode=mixed
ExecStart=/usr/local/bin/node /path/to/your/server.js

[Install]
WantedBy=multi-user.target

关于node.js - Node 子进程 : how to intercept signals like SIGINT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44788013/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com