Skip to content

Commit

Permalink
creating _teardown methods and moving shut down behavior into each mo…
Browse files Browse the repository at this point in the history
…dule from code
  • Loading branch information
evantahler committed Dec 5, 2012
1 parent b7e5a79 commit 8fdd275
Show file tree
Hide file tree
Showing 10 changed files with 286 additions and 175 deletions.
93 changes: 28 additions & 65 deletions actionHero.js
Expand Up @@ -6,7 +6,6 @@
var actionHero = function(){
var self = this;

self.running = false;
self.initalizers = {};
self.api = {};

Expand Down Expand Up @@ -53,6 +52,8 @@ actionHero.prototype.start = function(params, next){
restart: self.restart,
}

self.api.running = true;

if (params == null){params = {};}
self.startingParams = params;

Expand Down Expand Up @@ -117,7 +118,6 @@ actionHero.prototype.start = function(params, next){
self.api.bootTime = new Date().getTime();
self.api.log("server ID: " + self.api.id);
self.api.log(successMessage, ["green", "bold"]);
self.running = true;
if(next != null){
next(null, self.api);
}
Expand All @@ -128,75 +128,38 @@ actionHero.prototype.start = function(params, next){

actionHero.prototype.stop = function(next){
var self = this;

if(self.running == true){
if(self.api.running == true){
self.api.running = false;
self.api.log("Shutting down open servers and pausing tasks", "bold");
for(var i in self.api.watchedFiles){
self.api.fs.unwatchFile(self.api.watchedFiles[i]);
}
for(var worker_id in self.api.tasks.processTimers){
clearTimeout(self.api.tasks.processTimers[worker_id]);
}
// allow running timers to finish, but do no work on next cycle.
self.api.tasks.process = function(api, worker_id){ }

var cont = function(){
var closed = 0;
var neededClosed = 0;
if(self.api.configData.httpServer.enable){ neededClosed++; }
if(self.api.configData.tcpServer.enable){ neededClosed++; }

var checkForDone = function(serverType){
if(serverType != null){
self.api.log("The " + serverType + " server has ended its connections and closed");
}
if(closed == neededClosed){
closed = -1;
self.running = false;
self.api.pids.clearPidFile();
self.api.log("The actionHero has been stopped", "bold");
self.api.log("***");
if(typeof next == "function"){ next(null, self.api); }
}
}

if(self.api.configData.httpServer.enable){
self.api.webServer.server.on("close", function(){
for(var i in self.api.webServer.clientClearTimers){ clearTimeout(self.api.webServer.clientClearTimers[i]); }
closed++;
checkForDone("http");
});
if(self.api.configData.webSockets.enable){
self.api.webSockets.disconnectAll(self.api, function(){
self.api.webServer.server.close();
});
}else{
self.api.webServer.server.close();
}
var orderedTeardowns = {};
orderedTeardowns['watchedFiles'] = function(next){
self.api.log(" > teardown: watchedFiles", 'gray');
for(var i in self.api.watchedFiles){
self.api.fs.unwatchFile(self.api.watchedFiles[i]);
}
next();
}

if(self.api.configData.tcpServer.enable){
self.api.socketServer.gracefulShutdown(self.api, function(){
closed++;
checkForDone("tcpServer");
});
for(var i in self.api){
if(typeof self.api[i]._teardown == "function"){
(function(name) {
orderedTeardowns[name] = function(next){
self.api.log(" > teardown: " + name, 'gray');
self.api[name]._teardown(self.api, next);
};
})(i)
}
checkForDone();
}

// remove from the list of hosts
if(self.api.redis.enable){
clearTimeout(self.api.redis.pingTimer);
clearTimeout(self.api.redis.lostPeerTimer);
self.api.redis.client.lrem("actionHero:peers", 1, self.api.id, function(err, count){
if(count != 1){ self.api.log("Error removing myself from the peers list", "red"); }
self.api.redis.client.hdel("actionHero:peerPings", self.api.id, function(){
cont();
});
});
}else{
cont();

orderedTeardowns['_complete'] = function(){
self.api.pids.clearPidFile();
self.api.log("The actionHero has been stopped", "bold");
self.api.log("***");
if(typeof next == "function"){ next(null, self.api); }
}

self.api.async.series(orderedTeardowns);
}else{
self.api.log("Cannot shut down (not running any servers)");
if(typeof next == "function"){ next(null, self.api); }
Expand All @@ -206,7 +169,7 @@ actionHero.prototype.stop = function(next){
actionHero.prototype.restart = function(next){
var self = this;

if(self.running == true){
if(self.api.running == true){
self.stop(function(err){
self.start(self.startingParams, function(err, api){
api.log('actionHero restarted', "green");
Expand Down
95 changes: 50 additions & 45 deletions initializers/initActions.js
Expand Up @@ -121,66 +121,71 @@ var initActions = function(api, next)
});

api.processAction = function(api, connection, messageID, next){
if(connection.params.limit == null){
connection.params.limit = api.configData.general.defaultLimit;
}else{
connection.params.limit = parseFloat(connection.params.limit);
}
if(api.running != true){
connection.error = "the server is shutting down";
next(connection, true);
}else{
if(connection.params.limit == null){
connection.params.limit = api.configData.general.defaultLimit;
}else{
connection.params.limit = parseFloat(connection.params.limit);
}

if(connection.params.offset == null){
connection.params.offset = api.configData.general.defaultOffset;
}else{
connection.params.offset = parseFloat(connection.params.offset);
}

if (connection.error === null){
if(connection.type == "web"){ api.utils.processRoute(api, connection); }
connection.action = connection.params["action"];
if(api.actions[connection.action] != undefined){
api.utils.requiredParamChecker(api, connection, api.actions[connection.action].inputs.required);
if(connection.error === null){
process.nextTick(function() {
if(api.domain != null){
var actionDomain = api.domain.create();
actionDomain.on("error", function(err){
api.exceptionHandlers.action(actionDomain, err, connection, next);
});
actionDomain.run(function(){
if(connection.params.offset == null){
connection.params.offset = api.configData.general.defaultOffset;
}else{
connection.params.offset = parseFloat(connection.params.offset);
}

if (connection.error === null){
if(connection.type == "web"){ api.utils.processRoute(api, connection); }
connection.action = connection.params["action"];
if(api.actions[connection.action] != undefined){
api.utils.requiredParamChecker(api, connection, api.actions[connection.action].inputs.required);
if(connection.error === null){
process.nextTick(function() {
if(api.domain != null){
var actionDomain = api.domain.create();
actionDomain.on("error", function(err){
api.exceptionHandlers.action(actionDomain, err, connection, next);
});
actionDomain.run(function(){
api.actions[connection.action].run(api, connection, function(connection, toRender){
connection.respondingTo = messageID;
// actionDomain.dispose();
next(connection, toRender);
});
})
}else{
api.actions[connection.action].run(api, connection, function(connection, toRender){
connection.respondingTo = messageID;
// actionDomain.dispose();
next(connection, toRender);
});
})
}else{
api.actions[connection.action].run(api, connection, function(connection, toRender){
connection.respondingTo = messageID;
next(connection, toRender);
});
}
});
}
});
}else{
process.nextTick(function() {
connection.respondingTo = messageID;
next(connection, true);
});
}
}else{
process.nextTick(function() {
if(connection.action == "" || connection.action == null){ connection.action = "{no action}"; }
connection.error = new Error(connection.action + " is not a known action.");
if(api.configData.commonWeb.returnErrorCodes == true && connection.type == "web"){
connection.responseHttpCode = 404;
}
process.nextTick(function(){
connection.respondingTo = messageID;
next(connection, true);
next(connection, true);
});
}
}else{
if(connection.action == "" || connection.action == null){ connection.action = "{no action}"; }
connection.error = new Error(connection.action + " is not a known action.");
if(api.configData.commonWeb.returnErrorCodes == true && connection.type == "web"){
connection.responseHttpCode = 404;
}
process.nextTick(function(){
connection.respondingTo = messageID;
next(connection, true);
});
}
}else{
process.nextTick(function(){
connection.respondingTo = messageID;
next(connection, true);
});
}
}
}
Expand Down
77 changes: 72 additions & 5 deletions initializers/initCache.js
Expand Up @@ -5,21 +5,32 @@
var initCache = function(api, next){

api.cache = {};
api.cache.sweeperTimer = null;
api.cache.sweeperTimeout = 1000;

api.cache.stopTimers = function(api){
clearTimeout(api.cache.sweeperTimer);
}

api.cache._teardown = function(api, next){
api.cache.stopTimers(api);
next();
}

if(api.redis && api.redis.enable === true){

var redisCacheKey = "actionHero:cache";

api.cache.size = function(api, next){
api.redis.client.hlen(redisCacheKey, function(err, count){
next(count);
next(null, count);
});
}

api.cache.load = function(api, key, next){
api.redis.client.hget(redisCacheKey, key, function (err, cacheObj){
api.redis.client.hget(redisCacheKey, key, function(err, cacheObj){
if(err != null){ api.log(err, red); }
cacheObj = JSON.parse(cacheObj);
try{ var cacheObj = JSON.parse(cacheObj); }catch(e){ }
if(cacheObj == null){
if(typeof next == "function"){
process.nextTick(function() { next(new Error("Object not found"), null, null, null, null); });
Expand Down Expand Up @@ -48,12 +59,44 @@ var initCache = function(api, next){
});
};

api.cache.sweeper = function(api, next){
api.redis.client.hkeys(redisCacheKey, function(err, keys){
var started = 0;
var sweepedKeys = [];
keys.forEach(function(key){
started++;
api.redis.client.hget(redisCacheKey, key, function(err, cacheObj){
if(err != null){ api.log(err, red); }
try{ var cacheObj = JSON.parse(cacheObj); }catch(e){ }
if(cacheObj != null){
if(cacheObj.expireTimestamp < new Date().getTime()){
api.redis.client.hdel(redisCacheKey, key, function(err, count){
sweepedKeys.push(key);
started--;
if(started == 0 && typeof next == "function"){ next(err, sweepedKeys); }
});
}else{
started--;
if(started == 0 && typeof next == "function"){ next(err, sweepedKeys); }
}
}else{
started--;
if(started == 0 && typeof next == "function"){ next(err, sweepedKeys); }
}
});
});
if(keys.length == 0 && typeof next == "function"){ next(err, sweepedKeys); }
});
}

}else{

api.cache.data = {};

api.cache.size = function(api, next){
next(api.utils.hashLength(api.cache.data));
process.nextTick(function(){
next(null, api.utils.hashLength(api.cache.data));
});
}

api.cache.load = function(api, key, next){
Expand Down Expand Up @@ -83,6 +126,18 @@ var initCache = function(api, next){
if(typeof next == "function"){ process.nextTick(function() { next(null, true); }); }
}
};

api.cache.sweeper = function(api, next){
var sweepedKeys = [];
for (var i in api.cache.data){
var entry = api.cache.data[i];
if ( entry.expireTimestamp != null && entry.expireTimestamp < new Date().getTime() ){
sweepedKeys.push(i);
delete api.cache.data[i];
}
}
if(typeof next == "function"){ next(null, sweepedKeys); }
}
}

api.cache.save = function(api, key, value, expireTimeMS, next){
Expand Down Expand Up @@ -116,8 +171,20 @@ var initCache = function(api, next){
}
};

next();
api.cache.runSweeper = function(api){
clearTimeout(api.cache.sweeperTimer);
api.cache.sweeper(api, function(err, sweepedKeys){
if(sweepedKeys.length > 0){
api.log("cleaned " + sweepedKeys.length + " expired cache keys");
}
if(api.running){
api.cache.sweeperTimer = setTimeout(api.cache.runSweeper, api.cache.sweeperTimeout, api);
}
});
}
api.cache.runSweeper(api);

next();
}

/////////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit 8fdd275

Please sign in to comment.