actionhero
Version:
actionhero.js is a multi-transport API Server with integrated cluster capabilities and delayed tasks
131 lines (114 loc) • 3.79 kB
JavaScript
;
var cluster = require('cluster');
var readline = require('readline');
var os = require('os');
exports.start = function(binary, next){
var ActionheroPrototype = require(binary.actionheroRoot + '/actionhero.js').actionheroPrototype;
var actionhero = new ActionheroPrototype();
// number of ms to wait to do a forcible shutdown if actionhero won't stop gracefully
var shutdownTimeout = 1000 * 30;
if(process.env.ACTIONHERO_SHUTDOWN_TIMEOUT){
shutdownTimeout = parseInt(process.env.ACTIONHERO_SHUTDOWN_TIMEOUT);
}
var api = {};
var state;
var startServer = function(callback){
state = 'starting';
if(cluster.isWorker){ process.send({state: state}); }
actionhero.start(function(error, apiFromCallback){
if(error){
binary.log(error);
process.exit(1);
}else{
state = 'started';
if(cluster.isWorker){ process.send({state: state}); }
api = apiFromCallback;
checkForInernalStop();
if(typeof callback === 'function'){ callback(null, api); }
}
});
};
var stopServer = function(callback){
state = 'stopping';
if(cluster.isWorker){ process.send({state: state}); }
actionhero.stop(function(){
state = 'stopped';
if(cluster.isWorker){ process.send({state: state}); }
api = null;
if(typeof callback === 'function'){ callback(null, api); }
});
};
var restartServer = function(callback){
state = 'restarting';
if(cluster.isWorker){ process.send({state: state}); }
actionhero.restart(function(error, apiFromCallback){
if(error){ throw(error); }
state = 'started';
if(cluster.isWorker){ process.send({state: state}); }
api = apiFromCallback;
if(typeof callback === 'function'){ callback(null, api); }
});
};
var stopProcess = function(){
setTimeout(function(){
throw new Error('process stop timeout reached. terminating now.');
}, shutdownTimeout);
// finalTimer.unref();
stopServer(function(){
process.nextTick(function(){
process.exit();
});
});
};
var checkForInernalStopTimer;
var checkForInernalStop = function(){
clearTimeout(checkForInernalStopTimer);
if(actionhero.api.running !== true && state === 'started'){
process.exit(0);
}
checkForInernalStopTimer = setTimeout(checkForInernalStop, shutdownTimeout);
};
if(cluster.isWorker){
process.on('message', function(msg){
if(msg === 'start'){ startServer(); }
else if(msg === 'stop'){ stopServer(); }
else if(msg === 'stopProcess'){ stopProcess(); }
// in cluster, we cannot re-bind the port
// so kill this worker, and then let the cluster start a new worker
else if(msg === 'restart'){ stopProcess(); }
});
process.on('uncaughtException', function(error){
var stack;
try{
stack = error.stack.split(os.EOL);
}catch(e){
stack = [error];
}
process.send({uncaughtException: {
message: error.message,
stack: stack
}});
process.nextTick(process.exit);
});
process.on('unhandledRejection', function(reason, p){
process.send({unhandledRejection: {reason:reason, p:p}});
process.nextTick(process.exit);
});
}
process.on('SIGINT', function(){ stopProcess(); });
process.on('SIGTERM', function(){ stopProcess(); });
process.on('SIGUSR2', function(){ restartServer(); });
if(process.platform === 'win32' && !process.env.IISNODE_VERSION){
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on('SIGINT', function(){
process.emit('SIGINT');
});
}
// start the server!
startServer(function(){
next(false);
});
};