pm2
Version:
Production process manager for Node.JS applications with a built-in load balancer.
88 lines (74 loc) • 2.22 kB
JavaScript
;
var childProcess = require('child_process');
var spawn = childProcess.spawn;
var exec = childProcess.exec;
module.exports = function (pid, signal, callback) {
pid = parseInt(pid, 10);
if (isNaN(pid)) {
if (callback) return callback(new Error('pid must be a number'));
return;
}
if (process.platform === 'win32') {
exec('taskkill /pid ' + pid + ' /T /F', { windowsHide: true }, function (err) {
if (callback) return callback(err, [pid]);
});
return;
}
// Unix (Linux, macOS, FreeBSD)
// 1) Snapshot all processes in one ps call
// 2) Build the descendant tree in JS
// 3) Kill bottom-up (deepest children first)
var ps = spawn('ps', ['-e', '-o', 'pid=,ppid=']);
var allData = '';
ps.on('error', function (err) {
if (callback) return callback(err);
});
if (ps.stdout) {
ps.stdout.on('data', function (data) {
allData += data.toString('ascii');
});
}
ps.on('close', function (code) {
if (code !== 0 && allData.length === 0) {
killPid(pid, signal);
if (callback) return callback();
return;
}
var childrenMap = {};
var lines = allData.trim().split('\n');
lines.forEach(function (line) {
var parts = line.trim().split(/\s+/);
if (parts.length < 2) return;
var cpid = parseInt(parts[0], 10);
var ppid = parseInt(parts[1], 10);
if (isNaN(cpid) || isNaN(ppid)) return;
if (!childrenMap[ppid]) childrenMap[ppid] = [];
childrenMap[ppid].push(cpid);
});
// Collect all descendants depth-first
var descendants = [];
function collect(parentPid) {
var kids = childrenMap[parentPid];
if (!kids) return;
kids.forEach(function (kid) {
collect(kid);
descendants.push(kid);
});
}
collect(pid);
// Kill bottom-up: deepest children first, then root
var allPids = descendants.concat(pid);
allPids.forEach(function (dpid) {
killPid(dpid, signal);
});
if (callback) return callback(null, allPids);
});
};
function killPid(pid, signal) {
try {
process.kill(parseInt(pid, 10), signal);
} catch (err) {
if (err.code !== 'ESRCH')
console.error(err);
}
}