Socket.io et Dyno multiple sur le nœud Heroku.js app. WebSocket est fermé avant que la connexion ne soit établie

je construis une application déployée à Heroku qui utilise des Websockets.

Les websockets connexion fonctionne correctement lorsque j'utilise seulement 1 dyno, mais quand je l'échelle >1, j'obtiens les erreurs suivantes

POST http://****.herokuapp.com/socket.io/?EIO=2&transport=polling&t=1412600135378-1&sid=zQzJJ8oPo5p3yiwIAAAC 400 (Bad Request) socket.io-1.0.4.js: 2

connexion WebSocket pour 'ws://****.herokuapp.com/socket.io/?EIO=2&transport=websocket&sid=zQzJJ8oPo5p3yiwIAAAC" échec: WebSocket est fermé avant que la connexion soit établie. socket.io-1.0.4.js: 2

j'utilise L'adaptateur Redis pour activer plusieurs processus web

var io = socket.listen(server);
var redisAdapter = require('socket.io-redis');
var redis = require('redis');

var pub = redis.createClient(18049, '[URI]', {auth_pass:"[PASS]"});
var sub = redis.createClient(18049, '[URI]', {detect_buffers: true, auth_pass:"[PASS]"} );

io.adapter( redisAdapter({pubClient: pub, subClient: sub}) );

cela fonctionne sur localhost (que j'utilise foreman pour diriger, comme Heroku le fait, et je lance 2 Processus web, comme sur Heroku).

Avant I j'ai mis en œuvre l'adaptateur redis j'ai eu une erreur de prise de main de web-sockets, donc l'adaptateur a eu un certain effet. En outre, il fonctionne de temps en temps maintenant, je suppose que lorsque les sockets correspondent à la même Web dyno.

j'ai aussi essayé d'activer les sessions collantes, mais ça ne marche jamais.

var sticky = require('sticky-session');
sticky(1, server).listen(port, function (err) {
  if (err) {
    console.error(err);
    return process.exit(1);
  }
  console.log('Worker listening on %s', port);
});
22
demandé sur Smittey 2014-10-06 17:30:08

5 réponses

je suis le nœud.propriétaire de la plateforme js à Heroku.

WebSockets works on Heroku out-of-the-box across multiple dynos; socket.io (et d'autres libs en temps réel) utilisent des retombées sur des processus apatrides comme les sondages xhr qui se terminent sans affinité de session.

pour augmenter la taille de la prise.io apps, d'abord suivre toutes les instructions de socket.io:

ensuite, activez session affinity sur votre application (Ceci est une fonctionnalité gratuite):

18
répondu hunterloftis 2015-07-17 17:00:16

j'ai passé un moment à essayer de faire socket.io fonctionne dans une architecture multi-serveur, d'abord sur Heroku puis sur Openshift comme beaucoup le suggèrent.

la seule façon de le faire fonctionner sur les deux PAAS est de désactiver xhr-polling et de définir transports: ['websocket'] sur le client et le serveur.

sur Openshift, vous devez explicitement définir le port du serveur à 8000 (pour ws – 8443 pour wss sur socket.initialisation du client io, en utilisant le *.rhcloud.com serveur, comme expliqué dans cet article: http://tamas.io/deploying-a-node-jssocket-io-app-to-openshift / .

la stratégie de sondage ne fonctionne pas sur Heroku parce qu'elle ne supporte pas les sessions collantes ( https://github.com/Automattic/engine.io/issues/261 ), et sur Openshift il échoue en raison de cette question: https://github.com/Automattic/engine.io/issues/279 , qui, espérons-le, sera bientôt réparé.

donc, le seul la solution que j'ai trouvée jusqu'à présent, est de désactiver les sondages et d'utiliser le transport websocket seulement.

pour faire ça, avec socket.io > 1,0 côté serveur:

var app = express();
var server = require('http').createServer(app);

var socketio = require('socket.io')(server, {
  path: '/socket.io-client'
});
socketio.set('transports', ['websocket']);

côté client:

var ioSocket = io('<your-openshift-app>.rhcloud.com:8000' || '<your-heroku-app>.herokuapp.com', {
    path: '/socket.io-client'
    transports: ['websocket']
})

Espérons que cela aidera.

4
répondu qubird 2015-01-19 13:52:37

il se peut que vous ayez besoin de faire tourner RedisStore:

var session = require('express-session');
var RedisStore = require('connect-redis')(session);

app.use(session({
    store: new RedisStore(options),
    secret: 'keyboard cat'
}));

par Q ici: dynos multiples sur Heroku + socket.io diffuse

1
répondu aug2uag 2017-05-23 12:01:46

je sais que ce n'est pas une réponse normale, mais j'ai essayé de faire travailler des WebSockets sur Heroku pendant plus d'une semaine. Après de longues conversations avec le support client, J'ai finalement essayé OpenShift. Les WebSockets Heroku sont en beta, mais les WebSockets OpenShift sont stables. Mon code fonctionne sur OpenShift dans moins d'une heure.

http://www.openshift.com

Je ne suis d'aucune façon affiliée à OpenShift. Je suis juste un client satisfait (non-payant).

1
répondu Luc 2014-11-09 16:30:22

j'avais d'énormes problèmes avec ça. Il y avait un certain nombre de problèmes qui ont échoué simultanément ce qui en fait un cauchemar énorme. Assurez-vous de faire ce qui suit pour scale socket.io on heroku:

  1. si vous utilisez des clusters, assurez-vous d'implémenter socketio-sticky-session ou quelque chose de similaire
  2. l'url de connexion du client ne doit pas être https://example.com/socket.io/?EIO=3&transport=polling mais plutôt https://example.com/ notamment j'utilise https parce que heroku le soutient

  3. activer les cors dans socket.io

  4. spécifier uniquement les connexions websocket

pour vous et d'autres, ça pourrait être n'importe lequel d'entre eux.

si vous avez de la difficulté à configurer les clusters de session collante, voici mon code de travail

var http = require('http');
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
var sticky = require('socketio-sticky-session');
var redis = require('socket.io-redis');
var io;

if(cluster.isMaster){
  console.log('Inside Master');
  // create the worker processes
  for (var i = 0; i < numCPUs ; i++){
    cluster.fork();
  }
}
else {
  // The worker code to be run is written inside
  // the sticky().
}

sticky(function(){
  // This code runs inside the workers.
  // The sticky-session balances connection between workers based on their ip.
  // So all the requests from the same client would go to the same worker.
  // If multiple browser windows are opened in the same client, all would be
  // redirected to the same worker.
  io = require('socket.io')({transports:'websocket', 'origins' : '*:*'});
  var server = http.createServer(function(req,res){
    res.end('socket.io');
  })


  io.listen(server);
  // The Redis server can also be used to store the socket state
  //io.adapter(redis({host:'localhost', port:6379}));

  console.log('Worker: '+cluster.worker.id);
    // when multiple workers are spawned, the client
    // cannot connect to the cloudlet.

    StartConnect(); //this function connects my mongodb, then calls a function with io.on('connection', ..... socket.on('message'...... in relation to the io variable above

    return server;
}).listen(process.env.PORT || 4567, function(){
  console.log('Socket.io server is up ');
});

plus information: personnellement, cela fonctionnerait parfaitement à partir d'une session n'utilisant pas de websockets (j'utilise socket.io for a unity game. Il a fonctionné parfaitement de l'éditeur seulement!). Lors de la connexion à travers le navigateur si chrome ou firefox, il afficherait ces erreurs de prise de main, avec erreur 503 et 400.

0
répondu hydrix 2017-05-23 12:13:51