Node.js Process July 25, 2011
The Node.js process class is very helpful for cleanup purposes. You can imagine, when writing a rudimentary web server, you might also have a mechanism for tracking sessions. This was definitely the case for me, so we can easily keep track of who's logged in, without exposing much in the way of security.
Having not worked in a way to update all of my code without restarting the server, I have to restart the server when a change is made to the code in order for it to update. This in turn, deletes all of the sessions. I was thinking of a way to handle this, knowing of Node.js's process class, but where to put the code was not immediately obvious in my brain, but once I started coding for this exact purpose, it was a shame that I didn't think of it right away, just for the shear fact that I cannot lie, and I could say "Yeah I thought of it right away" :)
Here's the code:
function closeServer(errno){
console.log("Server closing, serializing sessions");
SessionManager.serialize(config.web.global.sessionStore, function(){
server.close();
process.exit(0);
});
}
process.on("SIGTERM", closeServer);
process.on("SIGINT", closeServer);
Luckily, killproc sends SIGTERM, and pressing CTRL+C sends a SIGINT signal. I've noticed kill also just sends SIGTERM, with SIGKILL being a very explicit option, so we may just have to listen for SIGTERM and SIGINT. Anyway.
sessionStore is the folder to store them in, and it clears them out each time and saves what's in memory, so we don't get months old sessions in there.
I just serialize them using JSON.stringify and deserialize with the counter, JSON.parse. It works beautifully.
The session ID is just a combination of the time, plus some user variables like user agent, hashed and hexed. Here's the code that serializes and deserializes.
SessionManager.prototype.serialize = function(path, callback){
var self = this;
fshelp.ensureFolder(path, function(err, exists){
fshelp.clearFolder(path, function(err, exists){
for (id in self.sessions){
if (!self.isExpired(self.sessions[id]))
fs.writeFileSync(path + id, JSON.stringify(self.sessions[id]), "utf8");
}
delete self.sessions;
callback();
});
});
}
SessionManager.prototype.deserialize = function(path, callback){
var self = this;
fshelp.ensureFolder(path, function(err, exists){
fs.readdir(path,function(err, files){
files.forEach(function(d){
var id = d.substring(d.lastIndexOf("/") + 1);
self.sessions[id] = JSON.parse(fs.readFileSync(path + d, "utf8"));
});
callback();
});
});
}
Now no one gets logged out when I have to restart my server for any reason!
Since all of this takes place at the end or the beginning, I figured to save some brain power and just use the synchronous operations for writing and reading the files.