Reputation: 2029
Not a duplicate of this: I can kill process fine, I want to know how to detect, within the process, that it's being killed, and gracefully shutdown.
I have a CLI tool to spawn and kill a child node.js process. The demo code is contained in these three files:
spawn.js
-- Will spawn the child.js
script, detached. For simplicity, I pipe the child's stdio
to an out.log
file
child.js
-- A simple counter which writes to a file, uses the readline
method to detect an emulated SIGINT in Windows
kill.js
-- Invokes a process.kill()
on the child process, using it's PID
spawn.js
'use strict';
var spawn = require('child_process').spawn;
var fs = require('fs');
var path = require('path');
var childFilePath = path.resolve(__dirname, 'child.js');
var out = fs.openSync('./out.log', 'a');
var err = fs.openSync('./out.log', 'a');
var options = {
detached: true,
stdio: ['ignore', out, err],
};
var child = spawn(process.execPath, [childFilePath], options);
child.unref();
child.js
'use strict';
var fs = require('fs');
var path = require('path');
if (process.platform === 'win32') {
console.log('win32 true');
var rl = require('readline').createInterface({
input: process.stdin,
output: process.stdout,
});
rl.on('SIGINT', function() {
process.emit('SIGINT');
});
}
process.on('SIGINT', function() {
console.log('SIGINT');
process.exit();
});
var filepath = path.resolve(__dirname, 'pid.txt');
fs.writeFile(filepath, process.pid);
var i = 0;
setInterval(function () {
console.log(i++);
}, 1000);
kill.js
'use strict';
var fs = require('fs');
var path = require('path');
var pidPath = path.resolve(__dirname, 'pid.txt');
fs.readFile(pidPath, 'utf8', function (err, data) {
if (err) {
return console.log(err);
}
process.kill(data, 'SIGINT');
});
When sending the process.kill(PID, 'SIGINT')
, it doesn't actually detect it as a SIGINT
in windows. I can run child.js
manually and use CTRL+C
to kill the process to trigger a SIGINT
, so I know that the readline
code is working (or maybe not since SIGINT
will trigger without the readline
code, but it will nonetheless trigger a SIGINT
)
Does process.kill()
not send the type of signal to a detached process? How do I detect that that a separate script is trying to kill my child process and shutdown gracefully?
Upvotes: 6
Views: 4455
Reputation: 620
There is a library kill-with-style to do this and works with detached process too. It has various options to set signal, timeout and retry options.
Upvotes: 0
Reputation: 8241
I have exactly the same problem. I noticed the rl.on("SIGINT")
is not working but rl.on("close")
works!
var rl = require('readline').createInterface({
input: process.stdin,
output: process.stdout,
})
rl.on('close', function() {
process.emit('SIGINT')
})
Here is my debug output
Sat Feb 17 2018 11:43:28 GMT+0800 (China Standard Time) process started (pid=6920)
Sat Feb 17 2018 11:43:28 GMT+0800 (China Standard Time) SIGINT captured! cleanup and then call process.exit(0)
Sat Feb 17 2018 11:43:28 GMT+0800 (China Standard Time) byebye! (code=0, signal=undefined)
Note that I'm not pretty sure that adding extra code to a subprocess is a good idea. Think about forking a non nodejs process, it might not be able to use such trick (e.g. redis-server, kdb+). I am still looking for a way to let spawn.js
to kill subprocess gracefully.
Update 1: Here is my initial problem reported to PM2 community https://github.com/Unitech/pm2/issues/3467
Upvotes: 1