289 votos

Node JS ECONNRESET

Estoy ejecutando una aplicación Express JS con socket.io para un chat y me aparece el siguiente error de forma aleatoria unas 5 veces durante 24h. El proceso del nodo se envuelve para siempre y se reinicia inmediatamente.

El problema es que el reinicio de Express echa a mis usuarios de sus habitaciones y nadie quiere eso.

El servidor web es proxy por HAProxy. No hay problemas de estabilidad de los sockets, sólo el uso de los transportes websockets y flashsockets. No puedo reproducir esto a propósito.

Este es el error con el nodo v0.10.11:

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: read ECONNRESET     //alternatively it s a 'write'
    at errnoException (net.js:900:11)
    at TCP.onread (net.js:555:19)
error: Forever detected script exited with code: 8
error: Forever restarting script for 2 time

EDITAR (2013-07-22)

Añadido el manejador de errores del cliente socket.io y el manejador de excepciones no capturadas. Parece que este último capta el error:

process.on('uncaughtException', function (err) {
  console.error(err.stack);
  console.log("Node NOT Exiting...");
});

Así que sospecho que no es un problema de socket.io sino una petición http a otro servidor que hago o una conexión mysql/redis. El problema es que la pila de errores no me ayuda a identificar el problema de mi código. Aquí está la salida del registro:

Error: read ECONNRESET
    at errnoException (net.js:900:11)
    at TCP.onread (net.js:555:19)

¿Cómo puedo saber cuál es la causa? ¿Cómo puedo sacar más provecho del error?

Ok, no es muy verboso pero aquí está el stacktrace con "longjohn":

Exception caught: Error ECONNRESET
{ [Error: read ECONNRESET]
  code: 'ECONNRESET',
  errno: 'ECONNRESET',
  syscall: 'read',
  __cached_trace__:
   [ { receiver: [Object],
       fun: [Function: errnoException],
       pos: 22930 },
     { receiver: [Object], fun: [Function: onread], pos: 14545 },
     {},
     { receiver: [Object],
       fun: [Function: fireErrorCallbacks],
       pos: 11672 },
     { receiver: [Object], fun: [Function], pos: 12329 },
     { receiver: [Object], fun: [Function: onread], pos: 14536 } ],
  __previous__:
   { [Error]
     id: 1061835,
     location: 'fireErrorCallbacks (net.js:439)',
     __location__: 'process.nextTick',
     __previous__: null,
     __trace_count__: 1,
     __cached_trace__: [ [Object], [Object], [Object] ] } }

Aquí sirvo el archivo de política del socket flash:

net = require("net")
net.createServer( (socket) =>
  socket.write("<?xml version=\"1.0\"?>\n")
  socket.write("<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n")
  socket.write("<cross-domain-policy>\n")
  socket.write("<allow-access-from domain=\"*\" to-ports=\"*\"/>\n")
  socket.write("</cross-domain-policy>\n")
  socket.end()
).listen(843)

¿Puede ser esta la causa?

255voto

e-sushi Puntos 5698

Puede que ya lo hayas adivinado: se trata de un error de conexión.

"ECONNRESET" significa que el otro lado de la conversación TCP cerró abruptamente su extremo de la conexión. Lo más probable es que esto se deba a uno o varios errores de protocolo de la aplicación. Podrías mirar los registros del servidor de la API para ver si se queja de algo.

Pero como también estás buscando una manera de comprobar el error y potencialmente depurar el problema, deberías echar un vistazo a " ¿Cómo depurar un error de cuelgue de socket en NodeJS? " que se publicó en stackoverflow en relación con una pregunta similar.

Solución rápida y sucia para el desarrollo :

Utilice longjohn se obtienen largas trazas de pila que contendrán las operaciones asíncronas.

Solución limpia y correcta : Técnicamente, en el nodo, siempre que emite un 'error' y nadie lo escucha, lanzará . Para que no lance, pon un listener y manéjalo tú mismo. Así podrás registrar el error con más información.

Para tener un oyente para un grupo de llamadas se puede utilizar dominios y también detectar otros errores en tiempo de ejecución. Asegúrate de que cada operación asíncrona relacionada con http(Servidor/Cliente) esté en diferentes dominio contexto comparando con las otras partes del código, el dominio escuchará automáticamente el error y lo propagará a su propio manejador. Así que sólo escuchas a ese manejador y obtienes los datos del error. Además, obtendrá más información de forma gratuita.

EDITAR (2013-07-22)

Como escribí arriba:

"ECONNRESET" significa que el otro lado de la conversación TCP cerró abruptamente su extremo de la conexión. Lo más probable es que esto se deba a uno o varios errores de protocolo de la aplicación. Podrías mirar los registros del servidor de la API para ver si se queja de algo.

Lo que también podría ser el caso: en momentos aleatorios, el otro lado está sobrecargado y simplemente mata la conexión como resultado. Si ese es el caso, depende de a qué te estés conectando exactamente

Pero una cosa es segura: efectivamente tienes un error de lectura en tu conexión TCP que provoca la excepción. Puedes comprobarlo mirando el código de error que has publicado en tu edición, que lo confirma.

40voto

Samson Puntos 1747

Un simple servidor tcp que tenía para servir el archivo de política de flash estaba causando esto. Ahora puedo atrapar el error usando un manejador:

# serving the flash policy file
net = require("net")

net.createServer((socket) =>
  //just added
  socket.on("error", (err) =>
    console.log("Caught flash policy server socket error: ")
    console.log(err.stack)
  )

  socket.write("<?xml version=\"1.0\"?>\n")
  socket.write("<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n")
  socket.write("<cross-domain-policy>\n")
  socket.write("<allow-access-from domain=\"*\" to-ports=\"*\"/>\n")
  socket.write("</cross-domain-policy>\n")
  socket.end()
).listen(843)

28voto

John Williams Puntos 769

Tuve un problema similar en el que las aplicaciones empezaron a dar errores después de una actualización de Node. Creo que esto se remonta a la versión v0.9.10 de Node:

  • net: no suprimir ECONNRESET (Ben Noordhuis)

Las versiones anteriores no se equivocaban con las interrupciones del cliente. Una interrupción de la conexión desde el cliente lanza el error ECONNRESET en Node. Creo que esta es una funcionalidad prevista para Node, por lo que la solución (al menos para mí) era manejar el error, lo que creo que hiciste en unCaught exceptions. Aunque yo lo manejo en el manejador net.socket.

Puedes demostrarlo:

Haz un simple servidor de sockets y consigue Node v0.9.9 y v0.9.10.

require('net')
    .createServer( function(socket) 
    {
           // no nothing
    })
    .listen(21, function()
     {
           console.log('Socket ON')
    })

Arranca con la v0.9.9 y luego intenta hacer FTP a este servidor. Estoy usando FTP y el puerto 21 sólo porque estoy en Windows y tengo un cliente FTP, pero no un cliente telnet a mano.

Entonces, desde el lado del cliente, sólo hay que romper la conexión. (Sólo estoy haciendo Ctrl-C)

No debería ver ningún ERROR cuando utilice Node v0.9.9, y ERROR cuando utilice Node v.0.9.10 y superior.

En producción, uso la v.0.10. algo y sigue dando el error. Una vez más, creo que esto es intencional y la solución es manejar el error en su código.

14voto

Ashish Kaila Puntos 227

Yo estaba enfrentando el mismo problema pero lo mitigé colocando: server.timeout = 0;

antes de server.listen. Aquí el servidor es el servidor http. El tiempo de espera por defecto es de 2 minutos según la API: http://nodejs.org/api/http.html

7voto

Joachim Isaksson Puntos 85969

Sí, su servicio del archivo de la política puede definitivamente causar el choque.

Para repetirlo, sólo tienes que añadir un retraso a tu código:

net.createServer( function(socket) 
{
  for(i=0; i<1000000000; i++);
  socket.write("<?xml version=\"1.0\"?>\n")
…

y utilizar telnet para conectarse al puerto. Si desconectas telnet antes de que el retardo haya expirado, obtendrás un fallo (excepción no capturada) cuando socket.write lance un error.

Para evitar el fallo aquí, sólo hay que añadir un manejador de errores antes de leer/escribir el socket:

net.createServer( function(socket) 
{
  for(i=0; i<1000000000; i++);
  socket.on('error', function() { console.log("error"); });
  socket.write("<?xml version=\"1.0\"?>\n")

Cuando intentes la desconexión anterior, sólo obtendrás un mensaje de registro en lugar de un fallo.

Y cuando hayas terminado, recuerda eliminar el retraso.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X