2

I would like to get a multi-process node. Workers are listening clients connections. I need pass sockets to master process because master process emit message to clients. Workers also need socket to emit message to clients.

Socket is a circular object and can't pass to a master process.

My code:

const cluster = require('cluster');

const http = require('http');
var io = require('socket.io');

var users;
var clients = {};
if (cluster.isMaster) {

function messageHandler(msg) {
   if (msg.usersarray) {
      usersarray = msg.usersarray;
      console.log(usersarray);
   }else if(msg.socket){
      clients[usersarray["manu"][0]] = msg.socket;
      clients[usersarray["manu"][0]].emit("hola","hola");               
   }
}

// Start workers and listen for messages containing notifyRequest
const numCPUs = require('os').cpus().length;
for (var i = 0; i < numCPUs; i++) {
  cluster.fork();
}

Object.keys(cluster.workers).forEach((id) => {
  cluster.workers[id].on('message', messageHandler);
});


}else {

// Create server & socket

var server = http.createServer(function(req, res){
    // Send HTML headers and message
    res.writeHead(404, {'Content-Type': 'text/html'});
    res.end('<h1>Aw, snap! 404</h1>');
});
server.listen(3000);
io = io.listen(server);

// Add a connect listener
io.sockets.on('connection', function(socket) {
    var hs = socket.handshake;
    console.log("socket connected");    
    if(users == undefined){
        users = {};
    }

    if(hs.query.usuario != undefined){

        if(users[hs.query.usuario] == undefined){
            users[hs.query.usuario] = new Array();
        }    

        users[hs.query.usuario].push(socket.id); // connected user with its socket.id
        clients[socket.id] = socket; // add the client data to the hash
        process.send({ usersarray: users});
        process.send({ socket: socket});
    }

    // Disconnect listener
    socket.on('disconnect', function() {
        console.log('Client disconnected.');
    });
});
}

in line process.send({ socket: socket}); Node js get error "TypeError: Converting circular structure to JSON"

-I used some module to transform circular object but don't working.

-I tried to pass socket id and then in master process, created new socket with this id but I didn't know to use it.

There is any posibility to pass socket from worker to master process?

Node js version: v5.5.0

Pepe
  • 21
  • 4

2 Answers2

1

Hm, I don't think it is possible what you are trying to do. When you create a cluster it means that you create separate processes (master + workers) which can only talk over the pipe.

Talking over the pipe means they can only send strings to each other. process.send tries to serialize a Javascript object as JSON (--> making a string out of it) using JSON.stringify. JSON for example cannot have functions, circles, etc. I just checked the socket object, it is very complex and contains functions (such as socket.emit()), so you cannot just serialize it and send it over the pipe.

Maybe you can check this or this on how to use clustered WebSockets.

It doesn't seem very trivial.. Maybe you can just pass CPU intensive tasks to some worker processes (via cluster or just spawning them yourself), send the results back to the master and let him do all the communication with the client?

Community
  • 1
  • 1
Kiechlus
  • 1,167
  • 12
  • 21
-1

I understand your purpose of broadcasting to all the node worker processes in a cluster, although you can not send socket component as such but there is a workaround for the purpose to be served. I will try an explain with an example :

Step 1: When a client action requires a broadcast :

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});
}) 

Step 2: On the cluster creation side

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");
}

Step 3: To Broadcast in the child process

-> Put this before io.on("connection") in 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 });
}
});

I hope its clear. Please comment if its confusing ... I will try and make it clear.

ram
  • 1
  • 2