简体   繁体   中英

Graceful kill off a detached node.js spawned child process in Windows

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.

Overview:

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


Code:

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');
});

Problem:

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 n.netheless 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?

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 (eg 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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM