¿Cómo depuro el error ECONNRESET en Node.js?
Estoy ejecutando una aplicación Express.js usando Socket.io para una aplicación web de chat y aparece el siguiente error al azar unas 5 veces durante 24 horas. El proceso del nodo se cierra para siempre y se reinicia inmediatamente.
El problema es que reiniciar Express expulsa a mis usuarios de sus salas y nadie quiere eso.
El servidor web está proxy por HAProxy. No hay problemas de estabilidad del socket, solo se usan transportes websockets y flashsockets. No puedo reproducir esto a propósito.
Este es el error con Node 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 (22/07/2013)
Se agregaron el controlador de errores del cliente socket.io y el controlador de excepciones no detectadas. Parece que este detecta el error:
process.on('uncaughtException', function (err) {
console.error(err.stack);
console.log("Node NOT Exiting...");
});
Entonces sospecho que no es un problema de Socket.io sino una solicitud 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 sé qué causa esto? ¿Cómo puedo sacar más provecho del error?
Ok, no es muy detallado, pero aquí está el seguimiento de pila 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?
Quizás ya lo hayas adivinado: es 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 más errores del protocolo de aplicación. Puede consultar los registros del servidor API para ver si se queja de algo.
Pero como también está buscando una manera de verificar el error y potencialmente depurar el problema, debería echar un vistazo a "¿ Cómo depurar un error de bloqueo 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 para obtener seguimientos de pila largos que contendrán las operaciones asíncronas.
Solución limpia y correcta : Técnicamente, en el nodo, cada vez que emites un 'error'
evento y nadie lo escucha, se lanzará . Para que no se tire, colóquele un oyente y manéjelo usted mismo. De esa manera podrá registrar el error con más información.
Para tener un oyente para un grupo de llamadas, puede usar dominios y también detectar otros errores en tiempo de ejecución. Asegúrese de que cada operación asíncrona relacionada con http(Servidor/Cliente) esté en un contexto de dominio diferente en comparación con las otras partes del código; el dominio escuchará automáticamente los
error
eventos y los propagará a su propio controlador. Entonces solo escuchas a ese controlador y obtienes los datos del error. También obtienes más información de forma gratuita.
EDITAR (22/07/2013)
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 más errores del protocolo de aplicación. Puede consultar los registros del servidor API para ver si se queja de algo.
Lo que también podría ser el caso: en momentos aleatorios, el otro lado se sobrecarga y, como resultado, simplemente corta la conexión. 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 causa la excepción. Puede verlo mirando el código de error que publicó en su edición, que lo confirma.
Un simple servidor TCP que tenía para entregar el archivo de política flash estaba causando esto. Ahora puedo detectar el error usando un controlador:
# 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)