diff --git a/README.md b/README.md index 5a3fb6a..e6d3992 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,13 @@ clusterMaster.quit() // not so graceful shutdown clusterMaster.quitHard() + +// listen to events to additional cleanup or shutdown +clusterMaster.emitter() + .on('resize', function (clusterSize) { }) + .on('restart', function () { }) + .on('quit', function () { }) + .on('quitHard', function () { }); ``` ## Methods @@ -57,19 +64,29 @@ clusterMaster.quitHard() Set the cluster size to `n`. This will disconnect extra nodes and/or spin up new nodes, as needed. Done by default on restarts. +Fires `resize` event with new clusterSize just before performing the +resize. ### clusterMaster.restart(cb) One by one, shut down nodes and spin up new ones. Callback is called -when finished. +when finished. Fires `restart` event just before performing restart. ### clusterMaster.quit() Gracefully shut down the worker nodes and then process.exit(0). +Fires `quit` event just before performing the shutdown. ### clusterMaster.quitHard() Forcibly shut down the worker nodes and then process.exit(1). +Fires `quitHard` event just before performing hard shut down. + +### clusterMaster.emitter() + +Retrieve the clusterMaster EventEmitter to be able to listen +to clusterMaster events. This emitter is also returned from +the original clusterMaster() constructor. ## Configs @@ -89,3 +106,14 @@ The `exec`, `env`, `argv`, and `silent` configs are passed to the the parent. Called in the context of the worker, so you can reply by looking at `this`. +## Events + +clusterMaster emits events on clusterMaster.emitter() when its methods +are called which allows you to respond and do additional cleanup right +before the action is carried out. + +* `resize` - fired on clusterMaster.resize(n), listener ex: fn(clusterSize) +* `restart` - fired on clusterMaster.restart(), listener ex: fn(oldWorkers) + `restartComplete` - fired when restart is completed +* `quit` - fired on clusterMaster.quit() +* `quitHard` - fired on clusterMaster.quitHard() diff --git a/cluster-master.js b/cluster-master.js index 555d18c..15bceb4 100644 --- a/cluster-master.js +++ b/cluster-master.js @@ -10,14 +10,17 @@ var cluster = require("cluster") , onmessage , repl = require('repl') , net = require('net') +, EventEmitter = require('events').EventEmitter +, masterEmitter = new EventEmitter() , fs = require('fs') , util = require('util') exports = module.exports = clusterMaster -exports.restart = restart -exports.resize = resize -exports.quitHard = quitHard -exports.quit = quit +exports.emitter = emitter +exports.restart = emitAndRestart +exports.resize = emitAndResize +exports.quitHard = emitAndQuitHard +exports.quit = emitAndQuit var debugStreams = {} function debug () { @@ -77,6 +80,8 @@ function clusterMaster (config) { // now make it the right size debug('resize and then setup repl') resize(setupRepl) + + return masterEmitter } function select (field) { @@ -126,9 +131,10 @@ function setupRepl () { }) var context = { repl: r, - resize: resize, - restart: restart, - quit: quit, + resize: emitAndResize, + restart: emitAndRestart, + quit: emitAndQuit, + quitHard: emitAndQuitHard, cluster: cluster, get size () { return clusterSize @@ -412,9 +418,9 @@ function quit () { function setupSignals () { try { - process.on("SIGHUP", restart) - process.on("SIGINT", quit) - process.on("SIGKILL", quitHard) + process.on("SIGHUP", emitAndRestart) + process.on("SIGINT", emitAndQuit) + process.on("SIGKILL", emitAndQuitHard) } catch (e) { // Must be on Windows, waaa-waaah. } @@ -423,3 +429,40 @@ function setupSignals () { if (!quitting) quitHard() }) } + +function emitter() { + return masterEmitter +} + +function emitAndResize(n) { + masterEmitter.emit('resize', n) + process.nextTick(function () { resize(n) }) +} + +function emitAndRestart(cb) { + if (restarting) { + debug("Already restarting. Cannot restart yet.") + return + } + var currentWorkers = Object.keys(cluster.workers).reduce(function (accum, k) { + accum[k] = { pid: cluster.workers[k].pid }; + return accum; + }, {}); + masterEmitter.emit('restart', currentWorkers); + process.nextTick(function () { + restart(function () { + masterEmitter.emit('restartComplete'); + if (cb) cb(); + }); + }); +} + +function emitAndQuit() { + masterEmitter.emit('quit') + process.nextTick(function () { quit() }) +} + +function emitAndQuitHard() { + masterEmitter.emit('quitHard') + process.nextTick(function () { quitHard() }) +} \ No newline at end of file