Is there a way to make changes to the code of a Node.JS application without restarting it.
For an example, if a file is being downloaded from the server at that time, is there a way to upgrade the server without the file transfer being disrupted?
Yes, it's possible with the cluster module.
Basically, you will start several slave instances of your app sharing the same port through a master process. The master will distribute incoming connections to the slaves.
When you want to restart, the master will, in sequence:
Here's some code to get you started (you'll need to npm install async underscore
).
Note: This is just to get you started. You should be prepared to handle unexpected slave failures and timeouts in a real setup.
var cluster = require('cluster');
var http = require('http');
var _ = require('underscore');
var async = require('async');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log('starting master with PID', process.pid);
// Fork workers.
var slaves = {};
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('fork', function (worker) {
slaves[worker.id] = worker;
});
cluster.on('exit', function (worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died');
delete slaves[worker.id];
// restart the worker
cluster.fork();
});
process.on('SIGHUP', function restartApp() {
console.log('restarting all slaves');
// important: force node.js to reload all js sources
delete require.cache;
var toRestart = _(slaves).values();
async.eachSeries(toRestart, function (slave, done) {
slave.kill('SIGTERM');
// when the new worker starts, proceed to the next instance
cluster.once('listening', function () {
done();
});
});
});
} else {
console.log('- starting slave with PID', process.pid);
// Workers can share any TCP connection
// In this case its a HTTP server
var server = http.createServer(function(req, res) {
res.writeHead(200);
res.end("hello world\n");
});
process.on('SIGTERM', function () {
// finish all current connections, then stop
server.close(function () {
process.exit(0);
});
});
server.listen(8000);
}
When you call `kill -HUP , you'll see that it restart all slaves in sequence:
worker 5156 died
- starting slave with PID 5164
worker 5157 died
- starting slave with PID 5165
worker 5158 died
- starting slave with PID 5166
worker 5159 died
- starting slave with PID 5167
While restarting, there are always 3 running slaves to handle incoming connections.
One last thing: in case you try, console.log
doesn't do anything in the slave SIGTERM handler because it has already been disconnected from the master.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With