Running node.js in production
I started my first node.js project in late 2013, working with this tech stack is an enjoyable experience but there were a couple very basic practices which weren't clear to me initially. Once we started using clustering to automatically restart the node process after errors and managed the process with upstart scripts we had a stable system which allowed this project to be successful.
- Using clustering to restart the node process if it fails due to uncaught exceptions allows the server to continue serving other requests and logs the error so you can review it later instead of immediately having to address the issue.
if (cluster.isMaster) {
cluster.fork();
cluster.on('disconnect', function(worker) {
console.error('disconnect!');
cluster.fork();
});
} else {
var app = express();
// do rest of express setup here
app.use(function domainMiddleware(req, res, next) {
var reqDomain = domain.create();
reqDomain.on('error', function (err) {
console.error('error', err.stack);
try {
// make sure we close down within 30 seconds
var killtimer = setTimeout(function() {
process.exit(1);
}, 30000);
// But don't keep the process open just for that!
killtimer.unref();
// Let the master know we're dead. This will trigger a
// 'disconnect' in the cluster master, and then it will fork
// a new worker.
cluster.worker.disconnect();
// try to send an error to the request that triggered the problem
res.statusCode = 500;
res.setHeader('content-type', 'text/plain');
res.end('Oops, there was a problem!\n');
} catch (er2) {
console.error('Error sending 500!', er2.stack);
}
});
reqDomain.run(next);
});
app.listen(port, function(){
console.log('node listening on port '+port);
});
module.exports = app;
This process is described in the official node docs
- Running my node sites on Ubuntu using upstart scripts ensure node starts up if the server is restarted. This will also daemonize your process so you can stop or restart it simply with ```service restart``` npm package upstart is excellent, going through the process will create something like the following script and store it in /etc/init/:
# firefly.conf
description "some website"
start on started networking
stop on runlevel [016]
limit nofile 1000000 1000000
console log
script
mkdir -p /home/webdev/web_server
cd /home/webdev/web_server
npm run production
end script
respawn
The first node.js project I put into production was replacing the Rails frontend of wordnik.com. This project helped speed up the site while reducing hosting costs. More details are on the Reverb Developers Blog Running off the Rails: Tackling Technical Debt with a Switch to Node.js
While I moved on from Reverb in late 2014 I am still happy to support Wordnik which recently spun off into a non profit. I adopted a word as soon as the program was announced: