web-dev-qa-db-fra.com

NodeJS | Cluster: Comment envoyer des données du maître à tous ou à un seul enfant / travailleur?

J'ai un script (stock) de travail de node

var cluster = require('cluster');
var http = require('http');
var numReqs = 0;

if (cluster.isMaster) {
  // Fork workers.
  for (var i = 0; i < 2; i++) {
    var worker = cluster.fork();

    worker.on('message', function(msg) {
      if (msg.cmd && msg.cmd == 'notifyRequest') {
        numReqs++;
      }
    });
  }

  setInterval(function() {
    console.log("numReqs =", numReqs);
  }, 1000);
} else {
  // Worker processes have a http server.
  http.Server(function(req, res) {
    res.writeHead(200);
    res.end("hello world\n");
    // Send message to master process
    process.send({ cmd: 'notifyRequest' });
  }).listen(8000);
}

Dans le script ci-dessus, je peux facilement envoyer des données du travailleur au processus maître. Mais comment envoyer des données du maître au travailleur/aux travailleurs? Avec des exemples, si possible.

26
htonus

Étant donné que cluster.fork est implémenté au-dessus de child_process.fork , vous pouvez envoyer des messages d'un maître au travailleur en utilisant worker.send({ msg: 'test' }), et d'un travailleur vers un maître par process.send({ msg: 'test' });. Vous recevez les messages comme suit: worker.on('message', callback) (du travailleur au maître) et process.on('message', callback); (du maître au travailleur).

Voici mon exemple complet, vous pouvez le tester en parcourant http: // localhost: 8000 / Ensuite, le travailleur enverra un message au maître et le maître répondra:

var cluster = require('cluster');
var http = require('http');
var numReqs = 0;
var worker;

if (cluster.isMaster) {
  // Fork workers.
  for (var i = 0; i < 2; i++) {
    worker = cluster.fork();

    worker.on('message', function(msg) {
      // we only want to intercept messages that have a chat property
      if (msg.chat) {
        console.log('Worker to master: ', msg.chat);
        worker.send({ chat: 'Ok worker, Master got the message! Over and out!' });
      }
    });

  }
} else {
  process.on('message', function(msg) {
    // we only want to intercept messages that have a chat property
    if (msg.chat) {
      console.log('Master to worker: ', msg.chat);
    }
  });
  // Worker processes have a http server.
  http.Server(function(req, res) {
    res.writeHead(200);
    res.end("hello world\n");
    // Send message to master process
    process.send({ chat: 'Hey master, I got a new request!' });
  }).listen(8000);
}
39
alessioalex

J'ai trouvé ce fil en cherchant un moyen d'envoyer un message à tous les processus enfants et j'ai heureusement pu le comprendre grâce aux commentaires sur les tableaux. Je voulais juste illustrer une solution potentielle pour envoyer un message à tous les processus enfants utilisant cette approche.

var cluster = require('cluster');
var http = require('http');
var numReqs = 0;
var workers = [];

if (cluster.isMaster) {
  // Broadcast a message to all workers
  var broadcast = function() {
    for (var i in workers) {
      var worker = workers[i];
      worker.send({ cmd: 'broadcast', numReqs: numReqs });
    }
  }

  // Fork workers.
  for (var i = 0; i < 2; i++) {
    var worker = cluster.fork();

    worker.on('message', function(msg) {
      if (msg.cmd) {
        switch (msg.cmd) {
          case 'notifyRequest':
            numReqs++;
          break;
          case 'broadcast':
            broadcast();
          break;
        }
    });

    // Add the worker to an array of known workers
    workers.Push(worker);
  }

  setInterval(function() {
    console.log("numReqs =", numReqs);
  }, 1000);
} else {
  // React to messages received from master
  process.on('message', function(msg) {
    switch(msg.cmd) {
      case 'broadcast':
        if (msg.numReqs) console.log('Number of requests: ' + msg.numReqs);
      break;
    }
  });

  // Worker processes have a http server.
  http.Server(function(req, res) {
    res.writeHead(200);
    res.end("hello world\n");
    // Send message to master process
    process.send({ cmd: 'notifyRequest' });
    process.send({ cmd: 'broadcast' });
  }).listen(8000);
}
8
Kevin Reilly

Voici comment j'ai implémenté une solution à un problème similaire. En vous connectant à cluster.on('fork'), vous pouvez attacher des gestionnaires de messages aux travailleurs au fur et à mesure qu'ils sont bifurqués (plutôt que de les stocker dans un tableau), ce qui présente l'avantage supplémentaire de traiter les cas de décès ou de déconnexion de travailleurs et un nouveau travailleur est fourchu.

Cet extrait enverrait un message du maître à tous travailleurs.

if (cluster.isMaster) {
    for (var i = 0; i < require('os').cpus.length; i++) {
        cluster.fork();
    }

    cluster.on('disconnect', function(worker) {
        cluster.fork();
    }

    // When a new worker process is forked, attach the handler
    // This handles cases where new worker processes are forked
    // on disconnect/exit, as above.
    cluster.on('fork', function(worker) {
        worker.on('message', messageRelay);
    }

    var messageRelay = function(msg) {
        Object.keys(cluster.workers).forEach(function(id) {
            cluster.workers[id].send(msg);
        });
    };
}
else {
    process.on('message', messageHandler);

    var messageHandler = function messageHandler(msg) {
        // Worker received message--do something
    };
}
4
LiquidPony

Vous devriez pouvoir envoyer un message du maître au travailleur comme ceci:

worker.send({message:'hello'})

parce que "cluster.fork est implémenté au-dessus de child_process.fork" (cluster.fork est implémenté au-dessus de child_process.fork)

1
cheng81

Je comprends votre objectif de diffusion vers tous les processus de travail de noeud dans un cluster, bien que vous ne puissiez pas envoyer de composant socket en tant que tel, mais il existe un travail autour du but à atteindre. Je vais essayer une explication avec un exemple:

Étape 1: lorsqu'une action client nécessite une diffusion:

Child.js (Process that has been forked) :

socket.on("BROADCAST_TO_ALL_WORKERS", function (data) 
{
    process.send({cmd : 'BROADCAST_TO_ALL_WORKERS', message :data.message});
}) 

Étape 2: côté création de cluster

Server.js (Place where cluster forking happens):

if (cluster.isMaster) {

  for (var i = 0; i < numCPUs; i++) {

    var worker = cluster.fork();

    worker.on('message', function (data) {
     if (data.cmd === "BROADCAST_TO_ALL_WORKERS") {
       console.log(server_debug_prefix() + "Server Broadcast To All, Message : " + data.message + " , Reload : " + data.reload + " Player Id : " + data.player_id);
        Object.keys(cluster.workers).forEach(function(id) {
            cluster.workers[id].send({cmd : "BROADCAST_TO_WORKER", message : data.message});
        });
      }
    });
  }

  cluster.on('exit', function (worker, code, signal) {
    var newWorker = cluster.fork();
    newWorker.on('message', function (data) {
      console.log(data);
      if (data.cmd === "BROADCAST_TO_ALL_WORKERS") {
        console.log(data.cmd,data);
        Object.keys(cluster.workers).forEach(function(id) {
            cluster.workers[id].send({cmd : "BROADCAST_TO_WORKER", message : data.message});
        });
      }
    });
  });
} 
else {
  //Node Js App Entry
  require("./Child.js");
}

Étape 3: pour diffuser dans le processus enfant -

-> Mettez ceci avant io.on ("connexion") dans Child.js

process.on("message", function(data){
    if(data.cmd === "BROADCAST_TO_WORKER"){
        io.sockets.emit("SERVER_MESSAGE", { message: data.message, reload: data.reload, player_id : data.player_id });
    }
});

J'espère que ça aide. Veuillez me faire savoir si des précisions supplémentaires sont nécessaires.

1
Raman