cluster-service
Advanced tools
Comparing version 1.0.5 to 1.0.6
@@ -66,6 +66,7 @@ var cluster = require("cluster"); | ||
cluster.worker.module = {}; | ||
// load the worker if not already loaded | ||
// async, in case worker loads cluster-service, we need to return before | ||
// it's avail | ||
setTimeout(function() { | ||
setImmediate(function() { | ||
cluster.worker.module = require(process.env.worker); | ||
@@ -80,3 +81,3 @@ if (global.cservice.locals.workerReady === undefined | ||
} | ||
}, 10); | ||
}); | ||
@@ -83,0 +84,0 @@ // start worker monitor to establish two-way relationship with master |
@@ -70,11 +70,3 @@ var async = require("async"), | ||
return function(cb) { | ||
// kill new worker if takes too long | ||
var newKiller = null; | ||
var newWorker = null; | ||
var exitListener = function() { | ||
if (newKiller) { | ||
clearTimeout(newKiller); | ||
} | ||
}; | ||
var w; | ||
var pendingWorker = null; | ||
@@ -89,11 +81,14 @@ if (worker.cservice.restart === false && explicitRestart === false) { | ||
// kill new worker if takes too long | ||
var newWorkerTimeout = null; | ||
var isNewWorkerTerminated = false; | ||
if (options.timeout > 0) { // start timeout if specified | ||
newKiller = setTimeout(function() { | ||
w = newWorker; | ||
newWorker = null; | ||
if (w) { | ||
w.removeListener("exit", exitListener); // remove temp listener | ||
w.kill("SIGKILL"); // go get'em, killer | ||
newWorkerTimeout = setTimeout(function() { | ||
if (pendingWorker) { | ||
isNewWorkerTerminated = true; | ||
pendingWorker.on('exit', function () { | ||
cb("timed out"); | ||
}); | ||
pendingWorker.kill("SIGKILL"); // go get'em, killer | ||
} | ||
cb("timed out"); | ||
}, options.timeout); | ||
@@ -103,14 +98,13 @@ } | ||
// lets start new worker | ||
newWorker = evt.service.newWorker(worker.cservice, function(err, newWorker){ | ||
var killer; | ||
newWorker.removeListener("exit", exitListener); // remove temp listener | ||
newWorker = null; | ||
if (newKiller) { // timeout no longer needed | ||
clearTimeout(newKiller); | ||
pendingWorker = evt.service.newWorker(worker.cservice, function(err) { | ||
pendingWorker = null; | ||
if (newWorkerTimeout) { // timeout no longer needed | ||
clearTimeout(newWorkerTimeout); | ||
} | ||
if (isNewWorkerTerminated) return; | ||
// ok, lets stop old worker | ||
killer = null; | ||
var oldWorkerTimeout = null; | ||
if (options.timeout > 0) { // start timeout if specified | ||
killer = setTimeout(function() { | ||
oldWorkerTimeout = setTimeout(function() { | ||
worker.kill("SIGKILL"); // go get'em, killer | ||
@@ -121,8 +115,8 @@ }, options.timeout); | ||
worker.on("exit", function() { | ||
if (killer) { | ||
clearTimeout(killer); | ||
if (oldWorkerTimeout) { | ||
clearTimeout(oldWorkerTimeout); | ||
} | ||
// exit complete, fire callback | ||
setTimeout(cb, 100); // slight delay in case other events are piled up | ||
setImmediate(cb); // slight delay in case other events are piled up | ||
}); | ||
@@ -129,0 +123,0 @@ |
@@ -31,25 +31,18 @@ /* jshint loopfunc:true */ | ||
worker.process.on( | ||
"exit", | ||
getExitHandler( | ||
evt | ||
, worker | ||
, options.timeout > 0 | ||
? setTimeout(getKiller(worker), options.timeout) | ||
: null | ||
, function() { | ||
workersToKill--; | ||
if (workersToKill === 0) { | ||
// no workers remain | ||
if (evt.service.workers.length === 0) { | ||
evt.locals.reason = "kill"; | ||
cservice.log("All workers shutdown. Exiting...".warn); | ||
evt.service.stop(options.timeout, cb); | ||
} else { | ||
cb(null, "Worker shutdown"); // DONE | ||
} | ||
} | ||
var killTimeout = options.timeout > 0 | ||
? setTimeout(getKiller(worker), options.timeout) | ||
: null; | ||
worker.on("exit", getExitHandler(evt, worker, killTimeout, function() { | ||
workersToKill--; | ||
if (workersToKill === 0) { | ||
// no workers remain | ||
if (evt.service.workers.length === 0) { | ||
evt.locals.reason = "kill"; | ||
cservice.log("All workers shutdown. Exiting...".warn); | ||
evt.service.stop(options.timeout, cb); | ||
} else { | ||
cb(null, "Worker shutdown"); // DONE | ||
} | ||
) | ||
); | ||
} | ||
})); | ||
@@ -108,3 +101,2 @@ require("../workers").exitGracefully(worker); | ||
clearTimeout(killer); | ||
killer = null; | ||
} | ||
@@ -111,0 +103,0 @@ |
@@ -67,36 +67,33 @@ var async = require("async"), | ||
return function(cb) { | ||
var pendingWorker; | ||
// kill new worker if takes too long | ||
var newKiller = null; | ||
var newWorker; | ||
var exitListener = function() { | ||
if (newKiller) { | ||
clearTimeout(newKiller); | ||
} | ||
}; | ||
var startTimeout = null; | ||
var isWorkerTerminated = false; | ||
if (options.timeout > 0) { // start timeout if specified | ||
newKiller = setTimeout(function() { | ||
if (!newWorker) | ||
startTimeout = setTimeout(function() { | ||
if (!pendingWorker) | ||
return; | ||
newWorker.removeListener("exit", exitListener); // remove temp listener | ||
newWorker.kill("SIGKILL"); // go get'em, killer | ||
cb("timed out"); | ||
isWorkerTerminated = true; | ||
pendingWorker.on('exit', function () { | ||
cb("timed out"); | ||
}); | ||
pendingWorker.kill("SIGKILL"); // go get'em, killer | ||
}, options.timeout); | ||
newKiller.unref(); | ||
startTimeout.unref(); | ||
} | ||
// lets start new worker | ||
newWorker = evt.service.newWorker(options, function(err, newWorker) { | ||
if (newWorker) { // won't exist if failure | ||
newWorker.removeListener("exit", exitListener); // remove temp listener | ||
pendingWorker = evt.service.newWorker(options, function(err) { | ||
pendingWorker = null; | ||
if (startTimeout) { // timeout no longer needed | ||
clearTimeout(startTimeout); | ||
} | ||
if (newKiller) { // timeout no longer needed | ||
clearTimeout(newKiller); | ||
newKiller = null; | ||
if (!isWorkerTerminated) { | ||
cb(err); | ||
} | ||
cb(err); | ||
}); | ||
}; | ||
} |
@@ -81,17 +81,16 @@ var async = require("async"), | ||
var pendingWorker; | ||
// kill new worker if takes too long | ||
var newKiller = null; | ||
var newWorker; | ||
var exitListener = function() { | ||
if (newKiller) { | ||
clearTimeout(newKiller); | ||
} | ||
}; | ||
var killer; | ||
var newWorkerTimeout = null; | ||
var isNewWorkerTerminated = false; | ||
if (options.timeout > 0) { // start timeout if specified | ||
newWorkerTimeout = setTimeout(function() { | ||
if (!pendingWorker) return; | ||
if (options.timeout > 0) { // start timeout if specified | ||
newKiller = setTimeout(function() { | ||
newWorker.removeListener("exit", exitListener);// remove temp listener | ||
newWorker.kill("SIGKILL"); // go get'em, killer | ||
cb("timed out"); | ||
isNewWorkerTerminated = true; | ||
pendingWorker.on('exit', function () { | ||
cb("timed out"); | ||
}); | ||
pendingWorker.kill("SIGKILL"); // go get'em, killer | ||
}, options.timeout); | ||
@@ -101,9 +100,8 @@ } | ||
// lets start new worker | ||
newWorker = evt.service.newWorker(options, function(err, newWorker) { | ||
if (newWorker) { // won't exist if failure | ||
newWorker.removeListener("exit", exitListener); // remove temp listener | ||
pendingWorker = evt.service.newWorker(options, function (err) { | ||
pendingWorker = null; | ||
if (newWorkerTimeout) { // timeout no longer needed | ||
clearTimeout(newWorkerTimeout); | ||
} | ||
if (newKiller) { // timeout no longer needed | ||
clearTimeout(newKiller); | ||
} | ||
if (err) { | ||
@@ -115,5 +113,5 @@ cb(err); | ||
// ok, lets stop old worker | ||
killer = null; | ||
var oldWorkerTimeout = null; | ||
if (options.timeout > 0) { // start timeout if specified | ||
killer = setTimeout(function() { | ||
oldWorkerTimeout = setTimeout(function() { | ||
worker.kill("SIGKILL"); // go get'em, killer | ||
@@ -124,8 +122,8 @@ }, options.timeout); | ||
worker.on("exit", function() { | ||
if (killer) { | ||
clearTimeout(killer); | ||
if (oldWorkerTimeout) { | ||
clearTimeout(oldWorkerTimeout); | ||
} | ||
// exit complete, fire callback | ||
setTimeout(cb, 250); // slight delay in case other events are piled up | ||
setImmediate(cb); // slight delay in case other events are piled up | ||
}); | ||
@@ -132,0 +130,0 @@ |
@@ -147,3 +147,3 @@ var cservice = require("../cluster-service"), | ||
"Content-Type": "text/json; charset=UTF-8", | ||
"Content-Length": body.length | ||
"Content-Length": Buffer.byteLength(body) | ||
} | ||
@@ -150,0 +150,0 @@ ); |
@@ -111,16 +111,3 @@ var cservice = require("../cluster-service"); | ||
return function(cb) { | ||
var tmpRequestCb = function(req, res) { | ||
if (res.headersSent === false) { | ||
// required to gracefully close connections on pending requests | ||
// this logic is typically only hit under VERY high load | ||
res.setHeader("Connection", "close"); | ||
} | ||
}; | ||
var tmpCloseCb = function() { | ||
server.removeListener("close", tmpCloseCb); | ||
//server.removeListener("request", tmpRequestCb); | ||
cb(null, true); | ||
}; | ||
server.on("close", tmpCloseCb); | ||
//server.on("request", tmpRequestCb); | ||
server.once("close", function() { cb(null, true); }); | ||
server.close(); | ||
@@ -127,0 +114,0 @@ }; |
@@ -63,3 +63,3 @@ var cservice = require("../cluster-service"), | ||
} | ||
process.exit(1); // graceful exit | ||
process.exit(0); // graceful exit | ||
}); | ||
@@ -66,0 +66,0 @@ } else { |
@@ -13,16 +13,16 @@ var cservice = require("../cluster-service"); | ||
cservice.trigger("shutdown", function() { | ||
if (cb) cb(null, "Shutting down..."); | ||
require("./http-server").close(); | ||
if (cservice.options.cli === true) { | ||
process.exit(1); | ||
} | ||
handleWorkersExited(cb); | ||
}, "all", timeout); | ||
} else { // gracefully shutdown | ||
if (cb) cb(null, "Shutting down..."); | ||
require("./http-server").close(); | ||
cservice.locals.state = 0; | ||
if (cservice.options.cli === true) { | ||
process.exit(1); | ||
} | ||
handleWorkersExited(cb); | ||
} | ||
} | ||
function handleWorkersExited(cb) { | ||
if (cb) cb(null, "Shutting down..."); | ||
require("./http-server").close(); | ||
cservice.locals.state = 0; | ||
if (cservice.options.cli === true) { | ||
process.exit(1); | ||
} | ||
} |
@@ -16,7 +16,9 @@ var cservice = require("../cluster-service"), | ||
worker = cworkers[k]; | ||
worker.pid = worker.process.pid; | ||
workers.push(worker); | ||
if (!worker.isDead || !worker.isDead()) { | ||
worker.pid = worker.process.pid; | ||
workers.push(worker); | ||
} | ||
} | ||
workers.send=send; | ||
workers.send = send; | ||
@@ -72,3 +74,3 @@ return workers; | ||
this.forEach(function(worker){ | ||
//worker.send.apply(worker, [].slice.apply(arguments)); | ||
worker.send.apply(worker, [].slice.apply(arguments)); | ||
}); | ||
@@ -75,0 +77,0 @@ } |
{ | ||
"name": "cluster-service", | ||
"version": "1.0.5", | ||
"version": "1.0.6", | ||
"author": { | ||
@@ -5,0 +5,0 @@ "name": "Aaron Silvas", |
@@ -98,3 +98,3 @@ # cluster-service | ||
cservice "server.js" --accessKey "123" | ||
cservice "server.js" --accessKey "123" | ||
@@ -189,8 +189,8 @@ Or via JSON config: | ||
* `start workerPath [cwd] { [timeout:60] }` - Gracefully start service, one worker at a time. | ||
* `restart all|pid { [timeout:60] }` - Gracefully restart service, waiting up to timeout before terminating workers. | ||
* `shutdown all|pid { [timeout:60] }` - Gracefully shutdown service, waiting up to timeout before terminating workers. | ||
* `start workerPath [cwd] { [timeout:60000] }` - Gracefully start service, one worker at a time. | ||
* `restart all|pid { [timeout:60000] }` - Gracefully restart service, waiting up to timeout before terminating workers. | ||
* `shutdown all|pid { [timeout:60000] }` - Gracefully shutdown service, waiting up to timeout before terminating workers. | ||
* `exit now` - Forcefully exits the service. | ||
* `help [cmd]` - Get help. | ||
* `upgrade all|pid workerPath { [cwd] [timeout:60] }` - Gracefully upgrade service, one worker at a time. (continuous deployment support). | ||
* `upgrade all|pid workerPath { [cwd] [timeout:60000] }` - Gracefully upgrade service, one worker at a time. (continuous deployment support). | ||
* `workers` - Returns list of active worker processes. | ||
@@ -197,0 +197,0 @@ * `health` - Returns health of service. Can be overidden by service to expose app-specific data. |
@@ -83,7 +83,10 @@ var cservice = require("../cluster-service"); | ||
it('Stop workers', function(done) { | ||
cservice.stop(30000, function() { | ||
cservice.stop(30000, function(err, msg) { | ||
assert.ok(!err, 'Error: ' + err); | ||
assert.equal( | ||
cservice.workers.length, | ||
0, | ||
"0 workers expected, but " + cservice.workers.length + " found" | ||
"0 workers expected, but " | ||
+ cservice.workers.length | ||
+ " found. Message: " + msg | ||
); | ||
@@ -90,0 +93,0 @@ done(); |
@@ -128,8 +128,11 @@ var cservice = require("../cluster-service"); | ||
it('Stop workers', function(done) { | ||
cservice.stop(30000, function() { | ||
it('Stop workers after upgrade', function(done) { | ||
cservice.stop(30000, function(err, msg) { | ||
assert.ok(!err, 'Received error ' + err); | ||
assert.equal( | ||
cservice.workers.length, | ||
0, | ||
"0 workers expected, but " + cservice.workers.length + " found" | ||
"0 workers expected, but " | ||
+ cservice.workers.length | ||
+ " found. Message: " + msg | ||
); | ||
@@ -180,7 +183,10 @@ done(); | ||
it('Stop workers', function(done) { | ||
cservice.stop(30000, function() { | ||
cservice.stop(30000, function(err, msg) { | ||
assert.ok(!err, 'Received error ' + err); | ||
assert.equal( | ||
cservice.workers.length, | ||
0, | ||
"0 workers expected, but " + cservice.workers.length + " found" | ||
"0 workers expected, but " | ||
+ cservice.workers.length | ||
+ " found. Message: " + msg | ||
); | ||
@@ -187,0 +193,0 @@ done(); |
@@ -0,0 +0,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
123896
3293