title: Socket.io, cluster, express and sync events
body: <p>I have a big problem sice 1 week. I try to convert my node.JS project actually run on single core to multi core with cluster.</p>
  
  <p>With websockets, at this moment, i have no problems for events but, for xhr-polling or jsonp-polling, i have big problems with socket.io on cluster mode.</p>
  
  <p>this is my server configuration : </p>
  
  <p>00-generic.js</p>
  
  <pre><code>'use strict';
  
  var http            = require('http'),
      os              = require('os'),
      cluster         = require('cluster');
  
  module.exports = function(done) {
      var app = this.express,
          port = process.env.PORT || 3000,
          address = '0.0.0.0';
  
      if(this.env == 'test'){
          port = 3030;
      }
  
      var self = this;
      var size = os.cpus().length;
  
      if (cluster.isMaster) {
          console.info('Creating HTTP server cluster with %d workers', size);
  
          for (var i = 0; i &lt; size; ++i) {
              console.log('spawning worker process %d', (i + 1));
              cluster.fork();
          }
  
          cluster.on('fork', function(worker) {
              console.log('worker %s spawned', worker.id);
          });
          cluster.on('online', function(worker) {
              console.log('worker %s online', worker.id);
          });
          cluster.on('listening', function(worker, addr) {
              console.log('worker %s listening on %s:%d', worker.id, addr.address, addr.port);
          });
          cluster.on('disconnect', function(worker) {
              console.log('worker %s disconnected', worker.id);
          });
          cluster.on('exit', function(worker, code, signal) {
              console.log('worker %s died (%s)', worker.id, signal || code);
              if (!worker.suicide) {
                  console.log('restarting worker');
                  cluster.fork();
              }
          });
      } else {
          http.createServer(app).listen(port, address, function() {
              var addr = this.address();
              console.log('listening on %s:%d', addr.address, addr.port);
              self.server = this;
              done();
          });
      }
  };
  </code></pre>
  
  <p>03-socket.io.js</p>
  
  <pre><code>"use strict";
  var _               = require('underscore'),
      socketio        = require('socket.io'),
      locomotive      = require('locomotive'),
      RedisStore      = require("socket.io/lib/stores/redis"),
      redis           = require("socket.io/node_modules/redis"),
      v1              = require(__dirname + '/../app/socket.io/v1'),
      sockets         = require(__dirname + '/../../app/socket/socket'),
      config          = require(__dirname + '/../app/global'),
      cluster         = require('cluster');
  
  module.exports = function () {
      if (!cluster.isMaster) {
          this.io = socketio.listen(this.server);
  
          var pub             = redis.createClient(),
              sub             = redis.createClient(),
              client          = redis.createClient();
  
          this.io.enable('browser client minification');  // send minified client
          this.io.enable('browser client etag');          // apply etag caching logic based on version number
          this.io.enable('browser client gzip');          // gzip the file
  
          this.io.set("store", new RedisStore({
              redisPub        : pub,
              redisSub        : sub,
              redisClient     : client
          }));
          this.io.set('log level', 2);
          this.io.set('transports', [
              'websocket',
              'jsonp-polling'
          ]);
          this.io.set('close timeout', 24*60*60);
          this.io.set('heartbeat timeout', 24*60*60);
  
          this.io.sockets.on('connection', function (socket) {
              console.log('connected with ' + this.io.transports[socket.id].name);
  
              // partie v1 @deprecated
              v1.events(socket);
  
              // partie v1.1 refaite
              _.each(sockets['1.1'], function(Mod) {
                  var mod = new Mod();
                  mod.launch({
                      socket  : socket,
                      io      : this.io
                  });
              }, this);
  
          }.bind(this));
      }
  };
  </code></pre>
  
  <p>With polling, the client connects from time to time on a different process than that initiated listeners. Similarly, the communication server to the client with emit. </p>
  
  <p>With a little searching, I found it necessary to pass by a store for socket.io to share the data connection. So I built RedisStore socket.io as shown in the documentation but even with that, I find myself with events not arriving safely and I still get this error message: </p>
  
  <pre><code>warn: client not handshaken client should reconnect
  </code></pre>
  
  <p><strong>EDIT</strong></p>
  
  <p>Now, the warn error is not called. I change the redisStore to socket.io-clusterhub BUT now, events are not always called. Sometimes as if the polling request was captured by another worker than that which began the listeners and so it nothing happens. Here is the new configuration:</p>
  
  <pre><code>'use strict';
  
  var http            = require('http'),
      locomotive      = require('locomotive'),
      os              = require('os'),
      cluster         = require('cluster'),
      config          = require(__dirname + '/../app/global'),
      _               = require('underscore'),
      socketio        = require('socket.io'),
      v1              = require(__dirname + '/../app/socket.io/v1'),
      sockets         = require(__dirname + '/../../app/socket/socket');
  
  module.exports = function(done) {
      var app = this.express,
          port = process.env.PORT || 3000,
          address = '0.0.0.0';
  
      if(this.env == 'test'){
          port = 3030;
      }
  
      var self = this;
      var size = os.cpus().length;
  
      this.clusterStore = new (require('socket.io-clusterhub'));
  
      if (cluster.isMaster) {
          for (var i = 0; i &lt; size; ++i) {
              console.log('spawning worker process %d', (i + 1));
              cluster.fork();
          }
  
          cluster.on('fork', function(worker) {
              console.log('worker %s spawned', worker.id);
          });
          cluster.on('online', function(worker) {
              console.log('worker %s online', worker.id);
          });
          cluster.on('listening', function(worker, addr) {
              console.log('worker %s listening on %s:%d', worker.id, addr.address, addr.port);
          });
          cluster.on('disconnect', function(worker) {
              console.log('worker %s disconnected', worker.id);
          });
          cluster.on('exit', function(worker, code, signal) {
              console.log('worker %s died (%s)', worker.id, signal || code);
              if (!worker.suicide) {
                  console.log('restarting worker');
                  cluster.fork();
              }
          });
      } else {
          var server = http.createServer(app);
  
          this.io = socketio.listen(server);
  
          this.io.configure(function() {
              this.io.enable('browser client minification');  // send minified client
              this.io.enable('browser client etag');          // apply etag caching logic based on version number
              this.io.enable('browser client gzip');          // gzip the file
  
              this.io.set('store', this.clusterStore);
              this.io.set('log level', 2);
              this.io.set('transports', [
                  'websocket',
                  'jsonp-polling'
              ]);
              //this.io.set('close timeout', 24*60*60);
              //this.io.set('heartbeat timeout', 24*60*60);
          }.bind(this));
  
          this.io.sockets.on('connection', function (socket) {
              console.log('connected with ' + this.io.transports[socket.id].name);
              console.log('connected to worker: ' + cluster.worker.id);
  
              // partie v1 @deprecated
              v1.events(socket);
  
              // partie v1.1 refaite
              _.each(sockets['1.1'], function(Mod) {
                  var mod = new Mod();
                  mod.launch({
                      socket  : socket,
                      io      : this.io
                  });
              }, this);
  
          }.bind(this));
  
          server.listen(port, address, function() {
              var addr = this.address();
              console.log('listening on %s:%d', addr.address, addr.port);
              self.server = this;
              done();
          });
      }
  };
  </code></pre>