admin管理员组

文章数量:1202578

I have a application in node.js.

This application is divided in 3 parts:

launcher.js, which start the two other part, and restart them on crash/update after handling cleaning.

app.js, which work on the computer himself.

server.js which is used to access log and different command.

The simplified code for launcher is:

var cluster = require('cluster'),
    exec = require('child_process').exec,
    server;

if (cluster.isMaster) {
    cluster.fork();
    server = exec('server.js');

    cluster.on('exit', function(worker, code, signal) {
        //Clean corrupted data, log crash if neccessary, reload source code for update ...
        cluster.fork();
    });
    server.on('exit', function () {
        //Same as for app, with a different handling of signal...
        server = exec('node server.js');
    });
} else {
    var self = require('app.js');
    self.start();
}

The good thing with cluster is that they are in the same process as the launcher, so I can handle some error without having to restart the app (just calling the right function inside the app for a "soft reboot" of itself), and keep everything in the same process.

While with exec, I m stuck with restarting the server, sometime without knowing what went wrong, and it mean having a subshell, which I dislike.

Is there a way to fork the cluster, but start a different code?

I have a application in node.js.

This application is divided in 3 parts:

launcher.js, which start the two other part, and restart them on crash/update after handling cleaning.

app.js, which work on the computer himself.

server.js which is used to access log and different command.

The simplified code for launcher is:

var cluster = require('cluster'),
    exec = require('child_process').exec,
    server;

if (cluster.isMaster) {
    cluster.fork();
    server = exec('server.js');

    cluster.on('exit', function(worker, code, signal) {
        //Clean corrupted data, log crash if neccessary, reload source code for update ...
        cluster.fork();
    });
    server.on('exit', function () {
        //Same as for app, with a different handling of signal...
        server = exec('node server.js');
    });
} else {
    var self = require('app.js');
    self.start();
}

The good thing with cluster is that they are in the same process as the launcher, so I can handle some error without having to restart the app (just calling the right function inside the app for a "soft reboot" of itself), and keep everything in the same process.

While with exec, I m stuck with restarting the server, sometime without knowing what went wrong, and it mean having a subshell, which I dislike.

Is there a way to fork the cluster, but start a different code?

Share Improve this question edited Nov 9, 2018 at 12:49 Ondrej Slinták 31.9k21 gold badges96 silver badges127 bronze badges asked Dec 13, 2013 at 14:24 DrakaSANDrakaSAN 7,8538 gold badges56 silver badges96 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 21

My solution to this:

var cluster = require("cluster");
if(cluster.isMaster){
    // Forking Worker1 and Worker2
    var worker1 = cluster.fork({WorkerName: "worker1"});
    var worker2 = cluster.fork({WorkerName: "worker2"});

    // Respawn if one of both exits
    cluster.on("exit", function(worker, code, signal){
        if(worker==worker1) worker1 = cluster.fork({WorkerName: "worker1"});        
        if(worker==worker2) worker2 = cluster.fork({WorkerName: "worker2"});
    });
} else {
    if(process.env.WorkerName=="worker1"){
         // Code of Worker1
    }

    if(process.env.WorkerName=="worker2"){
         // Code of Worker2
    }
}

A more dynamic example:

var cluster = require("cluster");

if(cluster.isMaster){

    // Forking Workers based on args    

    if(process.argv.length < 3){
      console.log("Usage: "+process.argv[1]+" module [module]");
    }

    process.argv.forEach(function (val, index, array) {
      // Don't use this script as worker (index 1 = self)
      if(index>1){
        // Resolve the module before spawning to prevent loop.
        try { require.resolve(val); spawn(val); }
        catch(e) { console.error("Module '"+val+"' not found"); }      
      }
    });

    cluster.on("exit", function(worker, code, signal){
        respawn(worker);
    });
} else {
    var self = require(process.env.WorkerScript);
    self.start();    
}


function spawn(script){
  cluster.fork({WorkerScript: script}).env = {WorkerScript: script};
}

function respawn(worker){
  console.log("Respawning: "+worker.env.WorkerScript)
  cluster.fork(worker.env).env = worker.env;
}
var cluster = require('cluster');

if (cluster.isMaster) {
    var app = cluster.fork(),
        server = cluster.fork();

    app.on('message', function () {
        app.send('app');
    });
    server.on('message', function () {
        server.send('server');
    });
} else {
    process.send('');
    process.on('message', function (code) {
        var self=require('/path/to/' + code + '.js');
        self.start();
    });
}

It work for starting two different cluster, but I m stuck at restarting the app.


EDIT: Final code, with working restart:

var VERSION = 0.3,
    util = require('util'),
    cluster = require('cluster'),
    PATH = process.argv[1].substr(0, process.argv[1].lastIndexOf('/') + 1),
    lib = [],
    childs = [];

function listen(child, i) {
    child.on('message', function(m) {
        if (m.type === 'REBOOT')
        {
            reboot();
        } else if (m.type === 'CODE1') {
            child.send({type: 'START', c: lib[i]});
        } else {
            log('ERROR', '');
        }
    });
    child.on('exit', function(worker, code, signal) {
        delete require.cache[require.resolve(PATH + lib[i])];
        childs[i]=cluster.fork();
        listen(childs[i], i);
    });        
}

function reboot() {
    i = 0;
    do
    {
        childs[i].kill();
        i = i + 1;
    }while (i < childs.length);
}

if (!cluster.isMaster) {
    var self;
    process.send({type:'START'});
    process.on('message', function(m) {
        if (m.type === 'START'){ 
            self = require(PATH + m.c);
            self.start();
        }
    });
} else {
    var i = 3;

    if (process.argv.length < 4)
    {
        log('ERROR', 'Not enought argument');
        log('USAGE', 'node launcher.js x ...');
        log('USAGE', '...: Apps to start (at least one)');
        process.exit(-1);
    } else {    
        do
        {
            lib.push(process.argv[i]);
            i = i + 1;
        }while (i < process.argv.length);

        i = 0;
        do
        {
                childs.push(cluster.fork());
                i = i + 1;
        }while(i < lib.length);

        i = 0;
        do
        {
            listen(childs[i], i);
            i = i + 1;
        }while(i < lib.length);
    }
}

You ll need to store cluster's code in different files and start this code with the paths to the files as arguments.

本文标签: javascriptNodejs Worker with differents code in clusterStack Overflow