Theo mặc định, các quy trình con được tạo bởi child_process.spawn()
có cùng số process group làm cha mẹ, trừ khi chúng được gọi với số {detached:true}
option.
Kết quả là kịch bản này sẽ hành xử khác nhau trong các môi trường khác nhau:
// 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');
});
Mở vỏ tương tác, một SIGINT từ CTL-C sẽ được gửi đến toàn bộ nhóm theo mặc định, vì vậy con không tách ra sẽ lấy SIGINT và thoát:
[email protected] $ node spawn-test.js
^Cjust ignore SIGINT
[email protected] [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
... nhưng các cuộc gọi đến kill(2)
chỉ có thể báo hiệu quá trình cha mẹ của bạn, vì vậy trẻ em sống sót:
[email protected] $ node spawn-test.js & echo $?
[2] 1234
[email protected] [another-terminal-window] $ kill -SIGINT 1234
[email protected] [another-terminal-window] $ ps aux | grep sleep
... sleep 101
... sleep 102
# both are still running
Tuy nhiên, pm2 là một con thú khác. Thậm chí nếu bạn thử các kỹ thuật nói trên, nó giết chết cây toàn bộ quá trình, bao gồm quá trình tách của bạn, ngay cả với một dài --kill-timeout
:
# Test pm2 stop
[email protected] $ pm2 start spawn-test.js --kill-timeout 3600
[email protected] $ pm2 stop spawn-test
[email protected] $ ps aux | grep sleep
# both are dead
# Test pm3 reload
[email protected] $ pm2 start spawn-test.js --kill-timeout 3600
[email protected] $ pm2 reload spawn-test
[email protected] $ ps aux | grep sleep
# both have different PIDs and were therefore killed and restarted
Điều này có vẻ giống như một lỗi trong PM2.
Tôi đã gặp các sự cố tương tự bằng cách sử dụng hệ thống init (systemd trong trường hợp của tôi) thay vì pm2, vì điều này cho phép kiểm soát tín hiệu tốt hơn.Trên hệ thống, các tín hiệu được gửi đến toàn bộ nhóm theo mặc định, nhưng bạn có thể sử dụng KillMode=mixed
để chỉ gửi tín hiệu đến tiến trình cha, nhưng vẫn SIGKILL con xử lý nếu chúng vượt quá thời gian chờ.
file đơn vị systemd của tôi trông như thế này:
[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
Cảm ơn cho câu trả lời tuyệt vời của bạn! –