Node.js http-proxy descarta solicitudes websocket

Bueno, he pasado más de una semana tratando de resolver esto sin éxito, así que si alguien tiene una pista, eres un héroe. Esta no será una pregunta fácil de responder, a menos que sea un tonto.

Estoy usando node-http-proxy para proxy sesiones pegajosas a 16 trabajadores de node.js que se ejecutan en diferentes puertos.

Utilizo los sockets web de Socket.IO para manejar un montón de diferentes tipos de solicitudes, y también uso las solicitudes tradicionales.

Cuando cambié mi servidor a un proxy a través de nodo-http-proxy, un nuevo problema surgió de que a veces, mi sesión Socket.IO no puede establecer una conexión.

Literalmente no puedo reproducirlo de forma estable para toda mi vida, con la única forma de convertirlo en lanzar mucho tráfico de varios clientes al servidor.

Si recargo el navegador del usuario, a veces se puede volver a conectar, y otras veces no.

Sesiones pegajosas

Tengo que hacer proxy de las sesiones adhesivas, ya que mi aplicación se autentica por trabajador, y así enruta una solicitud basada en su cookie Connect.SID (estoy usando conectar / expresar).

Vale un código

Este es mi archivo proxy.js que se ejecuta en el nodo y las rutas a cada uno de los trabajadores:

var http = require('http');
var httpProxy = require('http-proxy');

// What ports the proxy is routing to.
var data = {
  proxyPort: 8888,
  currentPort: 8850,
  portStart: 8850,
  portEnd: 8865,
};

// Just gives the next port number.
nextPort = function() {
  var next = data.currentPort++;
  next = (next > data.portEnd) ? data.portStart : next;
  data.currentPort = next;
  return data.currentPort;
};

// A hash of Connect.SIDs for sticky sessions.
data.routes = {}

var svr = httpProxy.createServer(function (req, res, proxy) {

  var port = false;

  // parseCookies is just a little function
  // that... parses cookies.
  var cookies = parseCookies(req);  

  // If there is an SID passed from the browser.
  if (cookies['connect.sid'] !== undefined) {

    var ip = req.connection.remoteAddress;

    if (data.routes[cookies['connect.sid']] !== undefined) {

      // If there is already a route assigned to this SID,
      // make that route's port the assigned port.
      port = data.routes[cookies['connect.sid']].port;
    } else {

      // If there isn't a route for this SID,
      // create the route object and log its
      // assigned port.
      port = data.currentPort;
      data.routes[cookies['connect.sid']] = {
        port: port,
      }

      nextPort();
    }

  } else {

    // Otherwise assign a random port, it will/
    // pick up a connect SID on the next go.
    // This doesn't really happen.
    port = nextPort();
  }

  // Now that we have the chosen port, 
  // proxy the request.
  proxy.proxyRequest(req, res, {
    host: '127.0.0.1',
    port: port
  });
}).listen(data.proxyPort);

// Now we handle WebSocket requests.
// Basically, I feed off of the above route
// logic and try to route my WebSocket to the
// same server regular requests are going to.
svr.on('upgrade', function (req, socket, head) {

  var cookies = parseCookies(req);  
  var port = false;

  // Make sure there is a Connect.SID,
  if (cookies['connect.sid'] != undefined) {

    // Make sure there is a route...
    if (data.routes[cookies['connect.sid']] !== undefined) {

      // Assign the appropriate port.
      port = data.routes[cookies['connect.sid']].port;
    } else {

      // this has never, ever happened, i've been logging it.
    }
  } else {

    // this has never, ever happened, i've been logging it.
  };

  if (port === false) {

    // this has never happened...
  };

  // So now route the WebSocket to the same port
  // as the regular requests are getting.
  svr.proxy.proxyWebSocketRequest(req, socket, head, {
    host: 'localhost',
    port: port
  });

});
Lado del cliente / Los fenómenos

El zócalo conecta así:

var socket = io.connect('http://whatever:8888');

Después de aproximadamente 10 segundos al iniciar sesión, recibo este error en este oyente, lo que no ayuda mucho.

socket.on('error', function (data) {
  // this is what gets triggered. ->
  // Firefox can't establish a connection to the server at ws://whatever:8888/socket.io/1/websocket/Nnx08nYaZkLY2N479KX0.
});

La solicitud Socket.IO GET que envía el navegador nunca regresa; simplemente se queda pendiente, incluso después de que el error vuelve, por lo que parece un error de tiempo de espera. El servidor nunca responde.

Lado del servidor - un trabajador

Así es como un trabajador recibe una solicitud de socket. Bastante simple. Todos los trabajadores tienen el mismo código, por lo que cree que uno de ellos recibiría la solicitud y la reconocería ...

app.sio.socketio.sockets.on('connection', function (socket) {
  // works... some of the time! all of my workers run this
  // exact same process.
});
Resumen

Eso es un montón de datos, y dudo que alguien esté dispuesto a confrontarlo, pero estoy totalmente perplejo, no sé dónde revisar a continuación, iniciar sesión a continuación, lo que sea, para resolverlo. He intentado todo lo que sé para ver cuál es el problema, en vano.

ACTUALIZAR

Bien, estoy bastante seguro de que el problema está en esta declaración en elPágina de inicio de nodo-http-proxy github:

proxy-nodo-nodo es <= 0.8.x compatible, si está buscando una versión compatible> = 0.10, por favor verifique caronte

Estoy ejecutando Node.js v0.10.13, y los fenómenos son exactamente como algunos han comentado en los temas de github sobre este tema: solo cae las conexiones de websocket al azar.

He intentado implementar caronte, la bifurcación 'más nueva', pero no está documentada en absoluto y he intentado todo lo posible para juntar sus documentos en una solución viable, pero no puedo conseguir que reenvíe websockets, mi Socket. IO baja las calificaciones a las encuestas.

¿Hay otras ideas sobre cómo conseguir que esto se implemente y funcione? node-http-proxy tiene 8200 descargas ayer! Claro que alguien está usando una compilación de Nodos de este año y procesando websockets ...

Lo que estoy buscando exactamente

Quiero lograr un servidor proxy (preferiblemente Nodo) que se dirija a varios trabajadores de node.js, y que enrute las solicitudes a través de sesiones adhesivas basadas en una cookie del navegador. Este proxy debería admitir de forma estable las solicitudes tradicionales, así como los sockets web.

O...

No me importa lograr lo anterior a través de los trabajadores de nodo agrupado, si eso funciona. Mi único requisito real es mantener sesiones rápidas basadas en una cookie en el encabezado de la solicitud.

Si hay una manera mejor de lograr lo anterior que lo que estoy intentando, estoy totalmente a favor.

Respuestas a la pregunta(3)

Su respuesta a la pregunta