196 lines
4.5 KiB
JavaScript
196 lines
4.5 KiB
JavaScript
|
|
/*!
|
|
* Cluster - repl
|
|
* Copyright (c) 2011 LearnBoost <dev@learnboost.com>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var net = require('net')
|
|
, repl = require('repl');
|
|
|
|
/**
|
|
* Enable REPL with all arguments passed to `net.Server#listen()`.
|
|
*
|
|
* Examples:
|
|
*
|
|
* cluster(server)
|
|
* .use(cluster.stats())
|
|
* .use(cluster.repl('/var/run/cluster'))
|
|
* .listen();
|
|
*
|
|
* In the terminal:
|
|
*
|
|
* $ sudo telnet /var/run/cluster
|
|
*
|
|
* @return {Function}
|
|
* @api public
|
|
*/
|
|
|
|
exports = module.exports = function(){
|
|
var args = arguments;
|
|
if (!args.length) throw new Error('repl() plugin requires port/host or path');
|
|
return function(master){
|
|
var server
|
|
, sockets = [];
|
|
|
|
|
|
// start repl
|
|
function start(){
|
|
// TCP or unix-domain socket repl
|
|
server = net.createServer(function(sock){
|
|
sockets.push(sock);
|
|
var ctx = repl.start('cluster> ', sock).context;
|
|
master.emit('repl socket', sock);
|
|
|
|
// augment socket to provide some formatting methods
|
|
sock.title = function(str){ this.write('\n \033[36m' + str + '\033[0m\n'); }
|
|
sock.row = function(key, val){ this.write(' \033[90m' + key + ':\033[0m ' + val + '\n'); }
|
|
|
|
// merge commands into context
|
|
// executing in context of master
|
|
Object.keys(exports).forEach(function(cmd){
|
|
ctx[cmd] = function(){
|
|
var args = Array.prototype.slice.call(arguments);
|
|
args.unshift(master, sock);
|
|
return exports[cmd].apply(master, args);
|
|
};
|
|
});
|
|
});
|
|
|
|
// Apply all arguments given
|
|
server.listen.apply(server, args);
|
|
}
|
|
|
|
// initial master starts immediately
|
|
// replacements starts when the previous
|
|
// has closed
|
|
master.on(master.isChild
|
|
? 'restart'
|
|
: 'start', start);
|
|
|
|
// restart notification
|
|
master.on('restarting', function(){
|
|
sockets.forEach(function(sock){
|
|
if (sock.fd) {
|
|
sock.write('\n\033[33mrestarting\033[0m - closing connection soon\n');
|
|
}
|
|
});
|
|
});
|
|
|
|
// close
|
|
master.on('close', function(){
|
|
sockets.forEach(function(sock){
|
|
sock.fd && sock.end();
|
|
});
|
|
if (server && server.fd) server.close();
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Define function `name`, with the given callback
|
|
* `fn(master, sock, ...)` and `description`.
|
|
*
|
|
* @param {String} name
|
|
* @param {Function} fn
|
|
* @param {String} desc
|
|
* @return {Object} exports for chaining
|
|
* @api public
|
|
*/
|
|
|
|
var define = exports.define = function(name, fn, desc){
|
|
(exports[name] = fn).description = desc;
|
|
return exports;
|
|
};
|
|
|
|
/**
|
|
* Display commmand help.
|
|
*/
|
|
|
|
define('help', function(master, sock){
|
|
sock.title('Commands');
|
|
Object.keys(exports).forEach(function(cmd){
|
|
if ('define' == cmd) return;
|
|
|
|
var fn = exports[cmd]
|
|
, params = fn.toString().match(/^function +\((.*?)\)/)[1]
|
|
, params = params.split(/ *, */).slice(2);
|
|
|
|
sock.row(
|
|
cmd + '(' + params.join(', ') + ')'
|
|
, fn.description);
|
|
});
|
|
sock.write('\n');
|
|
}, 'Display help information');
|
|
|
|
/**
|
|
* Spawn `n` additional workers with the given `signal`.
|
|
*/
|
|
|
|
define('spawn', function(master, sock, n, signal){
|
|
n = n || 1;
|
|
if (n < 0) {
|
|
n = Math.abs(n);
|
|
sock.write('removing ' + n + ' worker' + (n > 1 ? 's' : '')
|
|
+ ' with ' + (signal || 'SIGQUIT') + '\n');
|
|
master.remove(n, signal);
|
|
} else {
|
|
sock.write('spawning ' + n + ' worker' + (n > 1 ? 's' : '') + '\n');
|
|
master.spawn(n);
|
|
}
|
|
}, 'Spawn one or more additional workers, or remove one or more');
|
|
|
|
/**
|
|
* Output process ids.
|
|
*/
|
|
|
|
define('pids', function(master, sock){
|
|
sock.title('pids');
|
|
sock.row('master', process.pid);
|
|
master.children.forEach(function(worker){
|
|
sock.row('worker #' + worker.id, worker.proc.pid);
|
|
});
|
|
sock.write('\n');
|
|
}, 'Output process ids');
|
|
|
|
/**
|
|
* Kill the given worker by `id` and `signal`.
|
|
*/
|
|
|
|
define('kill', function(master, sock, id, signal){
|
|
var worker = master.children[id];
|
|
if (worker) {
|
|
worker.proc.kill(signal);
|
|
sock.write('sent \033[36m' + (signal || 'SIGTERM') + '\033[0m to worker #' + id + '\n');
|
|
} else {
|
|
sock.write('invalid worker id\n');
|
|
}
|
|
}, 'Send signal or SIGTERM to the given worker');
|
|
|
|
/**
|
|
* Gracefully shutdown.
|
|
*/
|
|
|
|
define('shutdown', function(master, sock){
|
|
master.close();
|
|
}, 'Gracefully shutdown server');
|
|
|
|
/**
|
|
* Hard shutdown.
|
|
*/
|
|
|
|
define('stop', function(master, sock){
|
|
master.destroy();
|
|
}, 'Hard shutdown');
|
|
|
|
/**
|
|
* Gracefully restart all workers.
|
|
*/
|
|
|
|
define('restart', function(master, sock){
|
|
master.restart();
|
|
}, 'Gracefully restart all workers'); |