0

I'm running Socket.io multi-threaded with the native cluster functionality provided by Node.js v0.6.0 and later (with RedisStore).

For every new change in state, the server iterates over each connection and sends a message if appropriate. Note: this isn't "broadcasting" to all connections, it's comparing server data with data the client sent on connection to decide whether to send the server data to that particular client. Consider this code sample:

io.sockets.clients().forEach(function (socket) {
  socket.get('subscription', function (err, message) {
   if(message.someProperty === someServerData) {
     socket.emit('position', someServerData);
   }
});

This worked fine when there was only one process, but now, the client receives a message for each Node process (ie. if there are 8 Node process running, all clients receive the messages 8 times).

I understand why the issue arises, but I'm not sure of a fix. How can I assign a 1-to-1 relation from one process to only on client. Perhaps something using NODE_WORKER_ID of Cluster?

This previous SO question seems somewhat related, although I'm not sure it's helpful.

This seems like a pretty common request. Surely, I must be missing something?

Community
  • 1
  • 1
David Chouinard
  • 6,466
  • 8
  • 43
  • 61
  • What exactly are you trying to do here? Authenticate the users somehow or.. what? – alessioalex Dec 20 '11 at 15:37
  • @alessioalex The server is reading a long stream of flight positions and sends out position updates to clients who subscribe to that flight (eg. the client subscribes to AWE150, and will receive all new positions related to AWE150). Thus, for every new position, the Node server iterates over all open connection and forwards that position to the appropriate connection. Perhaps my approach is wrong? – David Chouinard Dec 20 '11 at 15:56
  • @David Chouinard why don't you use rooms for that? client x joins room `AWE150` and when you data for that you do `io.sockets.to('AWE150').emit('position', somedata)` – 3rdEden Dec 20 '11 at 16:28
  • @3rdEden The conditions are much complicated that just a flight ident (lat/long box, tail numbers, idents, etc. and combinations of those features) – David Chouinard Dec 20 '11 at 16:49

1 Answers1

1

So if I get this straight you need to emit custom events from the server. You can do that by creating your own custom EventEmitter and triggering events on that emitter, for example:

var io = require('socket.io').listen(80);
    events = require('events'),
    customEventEmitter = new events.EventEmitter();


io.sockets.on('connection', function (socket) {
  // here you handle what happens on the 'positionUpdate' event
  // which will be triggered by the server later on
  eventEmitter.on('positionUpdate', function (data) {
    // here you have a function that checks if a condition between 
    // the socket connected and your data set as a param is met
    if (condition(data,socket)) {
      // send a message to each connected socket
      // if the condition is met
      socket.emit('the new position is...');
    }
  });
});

// sometime in the future the server will emit one or more positionUpdate events
customEventEmitter.emit('positionUpdate', data);

Another solution would be to have those users join the 'AWE150', so only they will receive updates for 'AWE150', like so:

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  if (client_is_interested_in_AWE) { socket.join('AWE150'); }
  io.sockets.in('AWE150').emit('new position here');
});

Resources:

http://spiritconsulting.com.ar/fedex/2010/11/events-with-jquery-nodejs-and-socket-io/

alessioalex
  • 62,577
  • 16
  • 155
  • 122