NodeJS / Cluster: как отправить данные от master всем или одному дочернему/рабочим?
У меня есть рабочий (стоковый) скрипт из узла
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 worldn");
// Send message to master process
process.send({ cmd: 'notifyRequest' });
}).listen(8000);
}
В приведенном выше сценарии я могу легко отправлять данные от рабочего к главному процессу. Но как отправить данные от мастера к рабочему / рабочим? С примерами, если это возможно.
5 ответов:
Потому что кластер.fork реализован поверх child_process.fork , Вы можете отправлять сообщения от мастера к рабочему с помощью
worker.send({ msg: 'test' }), а от рабочего к мастеру с помощьюprocess.send({ msg: 'test' });. Вы получаете такие сообщения:worker.on('message', callback)(от рабочего к мастеру) иprocess.on('message', callback);(от мастера к рабочему).Вот мой полный пример, вы можете проверить его, просмотрев http://localhost:8000 / затем рабочий пошлет сообщение мастеру, и мастер ответит:
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); }
Я нашел этот поток, когда искал способ отправить сообщение всем дочерним процессам,и, к счастью, смог выяснить это благодаря комментариям о массивах. Просто хотел проиллюстрировать потенциальное решение для отправки сообщения всем дочерним процессам, использующим этот подход.
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); }
Вот как я реализовал решение подобной проблемы. Подключившись к
cluster.on('fork'), Вы можете прикреплять обработчики сообщений к рабочим, когда они разветвляются (вместо того, чтобы хранить их в массиве), что имеет дополнительное преимущество в работе со случаями, когда рабочие умирают или отключаются, а новый работник разветвляется.Этот фрагмент будет посылать сообщение от мастера Всем работникам.
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 }; }
Вы должны быть в состоянии отправить сообщение от мастера к рабочему так:
worker.send({message:'hello'})Потому что " кластер.форк реализован поверх child_process.вилка " (кластер.форк реализован поверх child_process.вилка)
Я понимаю вашу цель широковещательной передачи всем рабочим процессам узла в кластере, хотя вы не можете отправить компонент сокета как таковой, но есть обходной путь для цели, которая будет обслуживаться. Я попробую объяснить на примере:
Шаг 1: Когда действие клиента требует широковещательной передачи:
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}); })Шаг 2: на стороне создания кластера
Server.js (Place where cluster forking happens): if (cluster.isMaster) { for (var i = 0; i < numCPUs; i++) {Var worker = кластер.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"); }Шаг 3: транслировать в ребенка процесс -
- > Поставьте это перед io.on ("соединение") в 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 }); } });Надеюсь, это поможет. Пожалуйста, дайте мне знать, если потребуются дополнительные разъяснения.
Comments