cluster-service
Version:
Turns your single process code into a fault-resilient multi-process service with built-in REST & CLI support
99 lines (84 loc) • 2.73 kB
JavaScript
var async = require("async"),
util = require("util"),
cservice = require("../../cluster-service");
module.exports = function(evt, cb, workerPath, options) {
var tasks;
var i;
options = options || {};
options.cwd = options.cwd || process.cwd();
options.count = parseInt(options.count) || 1;
options.timeout = parseInt(options.timeout) || 60000;
options.worker = workerPath;
if (typeof workerPath !== "string" || options.count < 1) {
cb("Invalid request. Try help start");
return;
}
evt.locals.reason = "start";
var originalAutoRestart = evt.locals.restartOnFailure;
evt.locals.restartOnFailure = false;
tasks = [];
cservice.log("Starting workers... timeout: " + (options.timeout || 0));
for (i = 0; i < options.count; i++) {
tasks.push(getTask(evt, options));
}
async.series(tasks, function(err) {
evt.locals.restartOnFailure = originalAutoRestart; // restore
if (err) {
cb(err);
} else {
cb(null, tasks.length + " workers started successfully");
}
});
};
module.exports.more = function(cb) {
cb(null, {
info: "Gracefully start service, one worker at a time.",
command: "start workerPath { \"option1\": \"value\" }",
"workerPath": [
"Path of worker file (i.e. /workers/worker) to start, absolute path, or",
"relative to cwd."
].join(' '),
"options": "An object of options.",
"* cwd": [
"Path to set as the current working directory. If not provided, existing",
"cwd will be used."
].join(' '),
"* count": "The number of workers to start, or 1 if not specified.",
"* timeout": [
"Timeout, in milliseconds, before terminating replaced workers. 0 for",
"infinite wait."
].join(' '),
"* ready":
"If false, will wait for workerReady event before assuming success."
});
};
function getTask(evt, options) {
return function(cb) {
var pendingWorker;
// kill new worker if takes too long
var startTimeout = null;
var isWorkerTerminated = false;
if (options.timeout > 0) { // start timeout if specified
startTimeout = setTimeout(function() {
if (!pendingWorker)
return;
isWorkerTerminated = true;
pendingWorker.on('exit', function () {
cb("timed out");
});
pendingWorker.kill("SIGKILL"); // go get'em, killer
}, options.timeout);
startTimeout.unref();
}
// lets start new worker
pendingWorker = evt.service.newWorker(options, function(err) {
pendingWorker = null;
if (startTimeout) { // timeout no longer needed
clearTimeout(startTimeout);
}
if (!isWorkerTerminated) {
cb(err);
}
});
};
}