From ef68ef5458eccfe06e04153956d0460a7ddf39f5 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 1 Apr 2016 16:59:46 +0200 Subject: [PATCH] #2061 fix process kill --- examples/sigint.js | 8 +++ lib/God/Methods.js | 36 ++++------- test/programmatic/signals.js | 119 ++++++++++++++++++++++++++++++++++- 3 files changed, 136 insertions(+), 27 deletions(-) create mode 100644 examples/sigint.js diff --git a/examples/sigint.js b/examples/sigint.js new file mode 100644 index 000000000..415fac3f8 --- /dev/null +++ b/examples/sigint.js @@ -0,0 +1,8 @@ + +process.on('SIGINT', function() { + // Do othing for tests +}); + +setInterval(function() { + console.log('I\'m alive'); +}, 2000); diff --git a/lib/God/Methods.js b/lib/God/Methods.js index be5958f33..33ffcf83d 100644 --- a/lib/God/Methods.js +++ b/lib/God/Methods.js @@ -17,19 +17,6 @@ var cst = require('../../constants.js'); var debug = require('debug')('pm2:methods'); var os = require('os'); -/** - * Kill process group in a cross platform way - * @method crossPlatformGroupKill - * @param int pid - * @param string sig - */ -function crossPlatformGroupKill(pid, sig) { - // This would have not been needed if node.js were able - // to handle group process kill on Windows (pid < -1). - if (os.platform() === 'win32') treekill(pid, sig); - else process.kill(-pid, sig); -} - /** * Description * @method exports @@ -248,7 +235,7 @@ module.exports = function(God) { else { console.log('Process with pid %d still alive after %sms, sending it SIGKILL now...', pid, kill_timeout); try { - crossPlatformGroupKill(parseInt(pid), 'SIGKILL'); + treekill(pid, 'SIGKILL'); } catch(e) { console.error('Process cannot be killed', e.message || e.stack || e); } @@ -271,20 +258,19 @@ module.exports = function(God) { var mode = pm2_env.exec_mode; - try { - if(pm2_env.treekill !== true) { + if (pm2_env.treekill !== true) { + try { process.kill(parseInt(pid), 'SIGINT'); + } catch(e) { + console.error('[SimpleKill] %s pid can not be killed', pid, e.stack, e.message); } - else { - if (mode.indexOf('cluster') === 0) { - treekill(parseInt(pid), 'SIGINT'); - } - else - crossPlatformGroupKill(parseInt(pid), 'SIGINT'); + } + else { + try { + treekill(pid, 'SIGINT'); + } catch(e) { + console.error('[Treekill] %s pid can not be killed', pid, e.stack, e.message); } - } catch(e) { - console.error('%s pid can not be killed', pid, e); - return cb(null, 'Cannot be killed'); } return God.processIsDead(pid, pm2_env, cb); diff --git a/test/programmatic/signals.js b/test/programmatic/signals.js index 429669862..20eda29f9 100644 --- a/test/programmatic/signals.js +++ b/test/programmatic/signals.js @@ -21,7 +21,7 @@ describe('Signal kill (+delayed)', function() { }); }); - describe('with 3000ms PM2_KILL_TIMEOUT', function() { + describe('with 3000ms PM2_KILL_TIMEOUT (environment variable)', function() { it('should set 3000ms to PM2_KILL_TIMEOUT', function(done) { process.env.PM2_KILL_TIMEOUT = 3000; @@ -62,7 +62,7 @@ describe('Signal kill (+delayed)', function() { }); }); - describe('with 1000ms PM2_KILL_TIMEOUT', function() { + describe('with 1000ms PM2_KILL_TIMEOUT (environment variable)', function() { it('should set 1000ms to PM2_KILL_TIMEOUT', function(done) { process.env.PM2_KILL_TIMEOUT = 1000; @@ -103,4 +103,119 @@ describe('Signal kill (+delayed)', function() { }); }); + describe('[CLUSTER MODE] with 1000ms PM2_KILL_TIMEOUT (environment variable)', function() { + it('should set 1000ms to PM2_KILL_TIMEOUT', function(done) { + process.env.PM2_KILL_TIMEOUT = 1000; + + pm2.update(function() { + done(); + }); + }); + + it('should start a script', function(done) { + pm2.start({ + script : './test/fixtures/signals/delayed_sigint.js', + name : 'delayed-sigint', + exec_mode : 'cluster' + }, function(err, data) { + proc1 = data[0]; + should(err).be.null; + setTimeout(done, 1000); + }); + }); + + it('should stop script after 1000ms', function(done) { + setTimeout(function() { + pm2.list(function(err, list) { + list[0].pm2_env.status.should.eql('stopping'); + }); + }, 500); + + setTimeout(function() { + pm2.list(function(err, list) { + list[0].pm2_env.status.should.eql('stopped'); + done(); + }); + }, 1500); + + pm2.stop('delayed-sigint', function(err, app) { + //done(err); + }); + + }); + + it('should reload script', function(done) { + setTimeout(function() { + pm2.list(function(err, list) { + list[0].pm2_env.status.should.eql('online'); + list[0].pm2_env.restart_time.should.eql(1); + done(); + }); + }, 1500); + + pm2.reload('delayed-sigint', function(err, app) { + //done(err); + }); + + }); + + it('should graceful reload script', function(done) { + setTimeout(function() { + pm2.list(function(err, list) { + list[0].pm2_env.status.should.eql('online'); + list[0].pm2_env.restart_time.should.eql(2); + done(); + }); + }, 1500); + + pm2.gracefulReload('delayed-sigint', function(err, app) { + //done(err); + }); + + }); + }); + + describe('with 4000ms via kill_timeout (json/cli option)', function() { + it('should set 1000ms to PM2_KILL_TIMEOUT', function(done) { + process.env.PM2_KILL_TIMEOUT = 1000; + + pm2.update(function() { + done(); + }); + }); + + it('should start a script with flag kill timeout to 4000ms', function(done) { + pm2.start({ + script : './test/fixtures/signals/delayed_sigint.js', + name : 'delayed-sigint', + exec_mode : 'cluster', + kill_timeout : 4000 + }, function(err, data) { + proc1 = data[0]; + should(err).be.null; + setTimeout(done, 1000); + }); + }); + + it('should stop script after 4000ms (and not 1000ms)', function(done) { + setTimeout(function() { + pm2.list(function(err, list) { + list[0].pm2_env.status.should.eql('stopping'); + }); + }, 1500); + + setTimeout(function() { + pm2.list(function(err, list) { + list[0].pm2_env.status.should.eql('stopped'); + done(); + }); + }, 4500); + + pm2.stop('delayed-sigint', function(err, app) { + //done(err); + }); + + }); + }); + });