clusterflock
Advanced tools
Comparing version 0.0.0 to 0.1.0
28
index.js
var cluster = require('cluster'), | ||
master = require('./lib/master'), | ||
os = require('os'), | ||
worker = require('./lib/worker'); | ||
module.exports = function(handler) { | ||
module.exports = function(handler, options) { | ||
options || (options = {}); | ||
setDefaultOptions(options); | ||
if (cluster.isMaster) { | ||
master(); | ||
master(options); | ||
} else { | ||
worker(handler); | ||
worker(handler, options); | ||
} | ||
}; | ||
function setDefaultOptions(options) { | ||
if (needsKey('numWorkers')) { | ||
options.numWorkers = os.cpus().length; | ||
} | ||
if (needsKey('port')) { | ||
options.port = process.env.PORT || 5000; | ||
} | ||
if (needsKey('timeout')) { | ||
options.timeout = 1000; | ||
} | ||
function needsKey(key) { | ||
return Object.keys(options).indexOf(key) === -1 | ||
} | ||
} |
var cluster = require('cluster'), | ||
logfmt = require('./logfmt'), | ||
os = require('os'); | ||
logfmt = require('./logfmt'); | ||
module.exports = function() { | ||
module.exports = function(options) { | ||
logfmt.log({ evt: 'starting master' }); | ||
for (var i = 0; i < os.cpus().length; i++) { | ||
for (var i = 0; i < options.numWorkers; i++) { | ||
cluster.fork(); | ||
} | ||
cluster.on('listening', function() { | ||
if (!this.listening) { | ||
logfmt.log({ evt: 'clusterflock is listening on port ' + options.port }); | ||
} | ||
this.listening = true; | ||
}); | ||
cluster.on('disconnect', function(worker) { | ||
logfmt.log({ evt: 'worker (pid ' + worker.process.pid + ') disconnected' }); | ||
if (!worker.suicide) { | ||
@@ -18,6 +27,6 @@ cluster.fork(); | ||
setupSignalHandlers(); | ||
setupSignalHandlers(options); | ||
}; | ||
function setupSignalHandlers() { | ||
function setupSignalHandlers(options) { | ||
process.on('SIGINT', function() { | ||
@@ -28,3 +37,3 @@ logfmt.log({ evt: 'received SIGINT, sending myself SIGTERM' }); | ||
process.once('SIGTERM', function() { | ||
process.on('SIGTERM', function() { | ||
logfmt.log({ evt: 'received SIGTERM, sending myself SIGQUIT' }); | ||
@@ -45,3 +54,3 @@ process.kill(process.pid, 'SIGQUIT'); | ||
process.kill(); | ||
}, 1000).unref(); | ||
}, options.timeout).unref(); | ||
@@ -48,0 +57,0 @@ cluster.disconnect(function() { |
@@ -1,9 +0,9 @@ | ||
var cluster = require('cluster'), | ||
http = require('http'), | ||
logfmt = require('./logfmt'); | ||
var http = require('http'), | ||
logfmt = require('./logfmt'); | ||
module.exports = function(handler) { | ||
module.exports = function(handler, options) { | ||
logfmt.log({ evt: 'starting worker' }); | ||
var server = http.createServer(handler); | ||
server.listen(process.env.PORT || 5000); | ||
server.listen(options.port); | ||
@@ -19,5 +19,7 @@ setupSignalHandlers(); | ||
// `once` ensures that workers are actually killed when a graceful shutdown | ||
// reaches its timeout (they receive another SIGTERM from the master) | ||
process.once('SIGTERM', function() { | ||
logfmt.log({ evt: 'received SIGTERM, waiting for master to send SIGQUIT' }); | ||
logfmt.log({ evt: 'ignoring SIGTERM, waiting for master to disconnect' }); | ||
}); | ||
} |
{ | ||
"name": "clusterflock", | ||
"version": "0.0.0", | ||
"version": "0.1.0", | ||
"description": "a clustering http server for node", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"test": "./node_modules/jasmine-node/bin/jasmine-node spec/" | ||
}, | ||
@@ -26,3 +26,7 @@ "repository": { | ||
"logfmt": "~0.21.0" | ||
}, | ||
"devDependencies": { | ||
"jasmine-node": "~1.13.1", | ||
"proxyquire": "~0.5.2" | ||
} | ||
} |
# clusterflock | ||
![flocking birds](http://cl.ly/image/0e3E400R1n0U/81938785_7755757d8a_m.jpg) | ||
clusterflock is a simple clustering HTTP server for Node. It accepts a single request handler and a hash of options. The goal of clusterflock is to eliminate my own repeated need for a simple clustering server that implements graceful worker shutdown and re-forking of dead workers. | ||
## Installation | ||
```sh | ||
$ npm install clusterflock --save | ||
``` | ||
## Usage | ||
By default, clusterflock will fork the number of workers equal to `os.cpus().length`. When it receives a `SIGINT` or `SIGTERM` signal, it will begin attempting to shut down gracefully by ceasing to receive requests and closing all servers after existing requests have been completed. | ||
The simplest use case of clusterflock is to pass it a single request handler function: | ||
```javascript | ||
var clusterflock = require('clusterflock'); | ||
clusterflock(function(req, res) { | ||
clusterflock(function (req, res) { | ||
res.end('ok'); | ||
}); | ||
``` | ||
Since clusterflock essentially just calls `http.createServer` in the worker process, anything that can be normally passed to that function can be passed to the `clusterflock` main function, including [express](http://expressjs.com) apps: | ||
```javascript | ||
var clusterflock = require('clusterflock'), | ||
express = require('express'), | ||
app = express(); | ||
app.use(express.bodyParser()); // &c. | ||
clusterflock(app); | ||
``` | ||
## Options | ||
Name | Type(s) | Default | Description | ||
------------ | ------------------ | -------------------------- | ------------------ | ||
`numWorkers` | `Number` | `os.cpus().length` | number of worker processes to fork | ||
`port` | `Number`, `String` | <code>process.env.PORT || 5000</code> | port the workers will listen on | ||
`timeout` | `Number` | `1000` | amount of time after receiving a graceful shutdown signal that the master will immediately kill workers | ||
## Testing | ||
To run the tests: | ||
```sh | ||
$ npm test | ||
``` | ||
## Contributing | ||
1. Fork it. | ||
2. Create a branch (`git checkout -b my-clusterflock`) | ||
3. Commit your changes (`git commit -am "add unicorns"`) | ||
4. Push to the branch (`git push origin my-clusterflock`) | ||
5. Open a [Pull Request](http://github.com/jclem/clusterflock/pulls) | ||
## Meta | ||
The photo in this readme is by Flickr user [Eugene Zemlyanskiy](http://www.flickr.com/photos/pictureperfectpose/81938785/). It has a [CC BY 2.0](http://creativecommons.org/licenses/by/2.0/) license. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
15357
11
350
1
66
2
3
2