Skip to content

Commit

Permalink
Merge pull request Unitech#4474 from aleksk/alekseyk/kill-send
Browse files Browse the repository at this point in the history
Adding optional switch to enable graceful shutdown on Windows
  • Loading branch information
Unitech authored Oct 30, 2019
2 parents 6dec187 + 7e6bcf4 commit 771e0ba
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 4 deletions.
3 changes: 3 additions & 0 deletions constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ var csts = {

WORKER_INTERVAL : process.env.PM2_WORKER_INTERVAL || 30000,
KILL_TIMEOUT : process.env.PM2_KILL_TIMEOUT || 1600,
KILL_SIGNAL : process.env.PM2_KILL_SIGNAL || 'SIGINT',
KILL_USE_SEND : process.env.PM2_KILL_USE_SEND || false,

PM2_PROGRAMMATIC : typeof(process.env.pm_id) !== 'undefined' || process.env.PM2_PROGRAMMATIC,
PM2_LOG_DATE_FORMAT : process.env.PM2_LOG_DATE_FORMAT !== undefined ? process.env.PM2_LOG_DATE_FORMAT : 'YYYY-MM-DDTHH:mm:ss'

Expand Down
20 changes: 17 additions & 3 deletions lib/God/Methods.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,18 +207,32 @@ module.exports = function(God) {
God.killProcess = function(pid, pm2_env, cb) {
if (!pid) return cb({msg : 'no pid passed or null'});

var mode = pm2_env.exec_mode;
if (cst.KILL_USE_SEND && typeof(pm2_env.pm_id) === 'number') {
var proc = God.clusters_db[pm2_env.pm_id];

if (proc && proc.send) {
try {
proc.send(cst.KILL_SIGNAL);
} catch (e) {
console.error('[SimpleKill] %s pid can not be killed', pid, e.stack, e.message);
}
return God.processIsDead(pid, pm2_env, cb);
}
else {
console.log('[SimpleKill] %s pid cannot be notified with send()', pid);
}
}

if (pm2_env.treekill !== true) {
try {
process.kill(parseInt(pid), process.env.PM2_KILL_SIGNAL || 'SIGINT');
process.kill(parseInt(pid), cst.KILL_SIGNAL);
} catch(e) {
console.error('[SimpleKill] %s pid can not be killed', pid, e.stack, e.message);
}
return God.processIsDead(pid, pm2_env, cb);
}
else {
treekill(parseInt(pid), process.env.PM2_KILL_SIGNAL || 'SIGINT', function(err) {
treekill(parseInt(pid), cst.KILL_SIGNAL, function(err) {
return God.processIsDead(pid, pm2_env, cb);
});
}
Expand Down
20 changes: 20 additions & 0 deletions test/e2e/cli/reload.sh
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,23 @@ should 'should not restart' 'restart_time: 0' 1
#$pm2 web
#$pm2 reload all
$pm2 kill

############### SEND() instead of KILL()
$pm2 kill
export PM2_KILL_USE_SEND='true'

$pm2 start signal-send.js
should 'should start processes' 'online' 1

OUT_LOG=`$pm2 prettylist | grep -m 1 -E "pm_out_log_path:" | sed "s/.*'\([^']*\)',/\1/"`
> $OUT_LOG

$pm2 reload signal-send.js
sleep 1

OUT=`grep "SIGINT" "$OUT_LOG" | wc -l`
[ $OUT -eq 1 ] || fail "Signal not received by the process name"
success "Processes sucessfully receives the signal"

unset PM2_KILL_USE_SEND
$pm2 kill
7 changes: 7 additions & 0 deletions test/fixtures/signal-send.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

setInterval(function() {
}, 1000);

process.on('message', function (msg) {
console.log(msg);
});
11 changes: 11 additions & 0 deletions test/fixtures/signals/delayed_send.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

setInterval(function() {
// Do nothing to keep process alive
}, 1000);

process.on('message', function (msg) {
if (msg === 'SIGINT') {
console.log('SIGINT message received but forbid exit');
}
});

130 changes: 129 additions & 1 deletion test/programmatic/signals.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ describe('Signal kill (+delayed)', function() {

it('should start a script', function(done) {
pm2.start({
script : './delayed_sigint.js',
script : './signals/delayed_sigint.js',
name : 'delayed-sigint'
}, function(err, data) {
proc1 = data[0];
Expand Down Expand Up @@ -206,3 +206,131 @@ describe('Signal kill (+delayed)', function() {
});

});

describe('Message kill (signal behavior override via PM2_KILL_USE_SEND, +delayed)', function() {
var proc1 = null;
var appName = 'delayed-send';

process.env.PM2_KILL_USE_SEND = true;

var pm2 = new PM2.custom({
cwd : __dirname + '/../fixtures',
});

after(function(done) {
pm2.delete('all', function(err, ret) {
pm2.kill(done);
});
});

before(function(done) {
pm2.connect(function() {
pm2.delete('all', function(err, ret) {
done();
});
});
});

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;

pm2.update(function() {
done();
});
});

it('should start a script', function(done) {
pm2.start({
script : './signals/delayed_send.js',
name : appName,
}, function(err, data) {
proc1 = data[0];
should(err).be.null();
setTimeout(done, 1000);
});
});

it('should stop script after 1000ms', function(done) {
setTimeout(function() {
pm2.describe(appName, function(err, list) {
should(err).be.null();
list[0].pm2_env.status.should.eql('stopping');
});
}, 500);

setTimeout(function() {
pm2.describe(appName, function(err, list) {
should(err).be.null();
list[0].pm2_env.status.should.eql('stopped');
done();
});
}, 1500);

pm2.stop(appName, function(err, app) {
//done(err);
});

});
});

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 : './signals/delayed_send.js',
name : appName,
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.describe(appName, function(err, list) {
should(err).be.null();
list[0].pm2_env.status.should.eql('stopping');
});
}, 500);

setTimeout(function() {
pm2.describe(appName, function(err, list) {
should(err).be.null();
list[0].pm2_env.status.should.eql('stopped');
done();
});
}, 1500);

pm2.stop(appName, function(err, app) {
//done(err);
});

});

it('should reload script', function(done) {
setTimeout(function() {
pm2.describe(appName, function(err, list) {
should(err).be.null();
list[0].pm2_env.status.should.eql('online');
done();
});
}, 1500);

pm2.reload(appName, function(err, app) {
//done(err);
});

});
});

});

0 comments on commit 771e0ba

Please sign in to comment.