UNPKG

egg-cluster

Version:
82 lines (71 loc) 2.22 kB
'use strict'; const { sleep } = require('./timer'); const awaitEvent = require('await-event'); const pstree = require('ps-tree'); module.exports = async function(subProcess, timeout) { const pid = subProcess.process ? subProcess.process.pid : subProcess.pid; const childPids = await getChildPids(pid); await Promise.all([ killProcess(subProcess, timeout), killChildren(childPids, timeout), ]); }; // kill process, if SIGTERM not work, try SIGKILL async function killProcess(subProcess, timeout) { // https://github.com/nodejs/node/pull/34312 (subProcess.process || subProcess).kill('SIGTERM'); await Promise.race([ awaitEvent(subProcess, 'exit'), sleep(timeout), ]); if (subProcess.killed) return; // SIGKILL: http://man7.org/linux/man-pages/man7/signal.7.html // worker: https://github.com/nodejs/node/blob/master/lib/internal/cluster/worker.js#L22 // subProcess.kill is wrapped to subProcess.destroy, it will wait to disconnected. (subProcess.process || subProcess).kill('SIGKILL'); } // kill all children processes, if SIGTERM not work, try SIGKILL async function killChildren(children, timeout) { if (!children.length) return; kill(children, 'SIGTERM'); const start = Date.now(); // if timeout is 1000, it will check twice. const checkInterval = 400; let unterminated = []; while (Date.now() - start < timeout - checkInterval) { await sleep(checkInterval); unterminated = getUnterminatedProcesses(children); if (!unterminated.length) return; } kill(unterminated, 'SIGKILL'); } function getChildPids(pid) { return new Promise(resolve => { pstree(pid, (err, children) => { // if get children error, just ignore it if (err) children = []; resolve(children.map(children => parseInt(children.PID))); }); }); } function kill(pids, signal) { for (const pid of pids) { try { process.kill(pid, signal); } catch (_) { // ignore } } } function getUnterminatedProcesses(pids) { return pids.filter(pid => { try { // success means it's still alive process.kill(pid, 0); return true; } catch (err) { // error means it's dead return false; } }); }