75 lines
1.6 KiB
JavaScript
75 lines
1.6 KiB
JavaScript
|
|
'use strict';
|
||
|
|
|
||
|
|
const cluster = require('cluster');
|
||
|
|
const EventEmitter = require('events').EventEmitter;
|
||
|
|
const defaults = require('lodash.defaults');
|
||
|
|
const cpuCount = require('os').cpus().length;
|
||
|
|
|
||
|
|
const DEFAULT_OPTIONS = {
|
||
|
|
workers: cpuCount,
|
||
|
|
lifetime: Infinity,
|
||
|
|
grace: 5000
|
||
|
|
};
|
||
|
|
|
||
|
|
const NOOP = () => {};
|
||
|
|
|
||
|
|
module.exports = function throng(options, startFunction) {
|
||
|
|
options = options || {};
|
||
|
|
let startFn = options.start || startFunction || options;
|
||
|
|
let masterFn = options.master || NOOP;
|
||
|
|
|
||
|
|
if (typeof startFn !== 'function') {
|
||
|
|
throw new Error('Start function required');
|
||
|
|
}
|
||
|
|
if (cluster.isWorker) {
|
||
|
|
return startFn(cluster.worker.id);
|
||
|
|
}
|
||
|
|
|
||
|
|
let opts = isNaN(options) ?
|
||
|
|
defaults(options, DEFAULT_OPTIONS) : defaults({ workers: options }, DEFAULT_OPTIONS);
|
||
|
|
let emitter = new EventEmitter();
|
||
|
|
let running = true;
|
||
|
|
let runUntil = Date.now() + opts.lifetime;
|
||
|
|
|
||
|
|
listen();
|
||
|
|
masterFn();
|
||
|
|
fork();
|
||
|
|
|
||
|
|
function listen() {
|
||
|
|
cluster.on('exit', revive);
|
||
|
|
emitter.once('shutdown', shutdown);
|
||
|
|
process
|
||
|
|
.on('SIGINT', proxySignal)
|
||
|
|
.on('SIGTERM', proxySignal);
|
||
|
|
}
|
||
|
|
|
||
|
|
function fork() {
|
||
|
|
for (var i = 0; i < opts.workers; i++) {
|
||
|
|
cluster.fork();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function proxySignal() {
|
||
|
|
emitter.emit('shutdown');
|
||
|
|
}
|
||
|
|
|
||
|
|
function shutdown() {
|
||
|
|
running = false;
|
||
|
|
for (var id in cluster.workers) {
|
||
|
|
cluster.workers[id].process.kill();
|
||
|
|
}
|
||
|
|
setTimeout(forceKill, opts.grace).unref();
|
||
|
|
}
|
||
|
|
|
||
|
|
function revive(worker, code, signal) {
|
||
|
|
if (running && Date.now() < runUntil) cluster.fork();
|
||
|
|
}
|
||
|
|
|
||
|
|
function forceKill() {
|
||
|
|
for (var id in cluster.workers) {
|
||
|
|
cluster.workers[id].kill();
|
||
|
|
}
|
||
|
|
process.exit();
|
||
|
|
}
|
||
|
|
};
|