doxout / recluster

Node clustering library with support for zero downtime reloading
522 stars 44 forks source link

How to get master to fork workers from new release? #8

Closed sandinmyjoints closed 10 years ago

sandinmyjoints commented 11 years ago

This is more of a conceptual question than an issue with recluster per se, so sorry about that, but any guidance would be appreciated. If I am managing deployment by directories that contain releases, then when I do a new release, how do I tell cluster to fork the new workers from the path to the new release code?

In other words:

Say release A is in /var/deploy/app/A, and symlink /var/deploy/app/current/ points to it. My app lives in app.js so my file argument to recluster is a relative path: var cluster = recluster("app.js");.

My simple cluster master script lives in cluster.js. I start up a master process via cd /var/deploy/app/A ; node cluster.js which forks a few app.js workers using the code in /var/deploy/app/A. The cwd of the master and the workers is /var/deploy/app/A.

Now I deploy release B to /var/deploy/app/B and update /var/deploy/app/current to point there. I send SIGUSR2 to master. master's cwd is still /var/deploy/app/A, so it is going to fork new workers from there rather than from /var/deploy/app/B.

One solution to this is: 1) explicitly use the /current symlink when starting the cluster master: cd /var/deploy/app/current ; node /var/deploy/app/current/cluster.js. 2) specify the file argument to cluster using the symlink from the master process:

var workerPath = process.argv[1].replace("cluster", "app");
var cluster    = recluster(workerPath);

Because the symlink is updated to the new release before SIGUSR2 is sent, the new workers will be forked from the new release.

In practice, I am using Chef and Upstart which complicates things somewhat. But ultimately I want to send a signal to the master process (via service <app name> reload) that will cause it to fork new workers from the new code release that Chef just deposited onto the server. Without the symlink, I haven't thought of a way to keep the same master process around but get it to fork workers from the new code. Do you have any thoughts on this?

spion commented 11 years ago

I'm afraid that symlinks are the only way for now. Thats because setupMaster from the cluster module can only be called once.

However, this can probably be worked around by writing a generic worker.js that takes the path to the script from env, then simply require()s it. If we do that, then .reload() could take an optional argument - the path to the new worker module.

But this still won't solve SIGUSR2-based reloads by itself. Your cluster.js will have to ask for configuration (e.g. to open and read a config file - or perhaps to open a unix socket where it can take reload commands). recluster wont do that as it aims to be a minimal library which can be used in any context - but once it supports arguments to cluster.reload this should be easy to implement.