Skip to content

Instantly share code, notes, and snippets.

@davidwood
Created April 30, 2012 14:46
Show Gist options
  • Save davidwood/2558904 to your computer and use it in GitHub Desktop.
Save davidwood/2558904 to your computer and use it in GitHub Desktop.
Basic node 0.6.x cluster skeleton
var http = require('http');
var app = module.exports = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end();
});
// Require the modules
var cluster = require('cluster'),
fs = require('fs'),
path = require('path');
// Production flag
var isProduction = process.env.NODE_ENV == 'production';
/* CLUSTER */
// Current PID path (expects a directory under root named pids)
var PIDS = path.join(__dirname, 'pids');
// Clear all PIDs
function clearPids() {
var filenames = fs.readdirSync(PIDS);
for (var i = 0, len = filenames.length; i < len; ++i) {
var filename = filenames[i];
if (path.extname(filename) == '.pid') clearPid(filename);
}
};
// Clear PID
function clearPid(pid) {
fs.unlinkSync(path.join(PIDS, pid));
};
// Write the current PID
function writePid() {
// Write the current PID
var filename = path.join(PIDS, cluster.isMaster ? 'master.pid' : 'worker.' + process.pid + '.pid');
fs.writeFileSync(filename, process.pid, 'utf8');
};
// Gracefully kill workers by sending a SIGQUIT
function killWorkers() {
// Read the files in the pids folder
var filenames = fs.readdirSync(PIDS);
for (var i = 0, len = filenames.length; i < len; ++i) {
var filename = filenames[i];
if (filename.substring(0, 7) == 'worker.' && path.extname(filename) == '.pid') {
// READ the PID and send a SIGQUIT
var pid = fs.readFileSync(path.join(PIDS, filename));
if (pid && pid != '') process.kill(pid, 'SIGQUIT');
}
}
};
/* APPLICATION LOGIC */
// Check if master or worker
if (isProduction && cluster.isMaster) {
// Clear all PIDs
clearPids();
// Write the current PID
writePid();
// Register restart handler
process.on('SIGUSR2', killWorkers);
// Reload worker on death
cluster.on('death', function(worker) {
console.log('Worker ' + worker.pid + ' died... restarting');
// Clear the PID file
clearPid('worker.' + worker.pid + '.pid');
cluster.fork();
});
// Create a workers per CPU
for (var i = 0, count = require('os').cpus().length; i < count; ++i) {
cluster.fork();
}
} else {
if (isProduction) {
// Write the current PID
writePid();
console.log('Worker ' + process.pid + ' started');
} else {
clearPids();
}
// Create the application
var app = require('./app');
if (isProduction) {
// Register restart handler
process.once('SIGQUIT', function() {
// Shutdown your application here
app.close()
process.exit();
});
}
// Start the server
app.listen(8000);
console.log("HTTP server listening on port %d", 8000);
}
@davidwood
Copy link
Author

The master and worker processes write their PID to a file in a directory under root named pids. This expects that the directory exists and is writable.

The master handles SIGUSR2 as a graceful restart, by dispatching a SIGQUIT to all workers, which executes the callback on line 82.

@davidwood
Copy link
Author

Running node server.js will spin up the application as a single process not using cluster. Running NODE_ENV=production node server.js will us cluster and create one worker per CPU core.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment