Ich m läuft eine Express js Anwendung mit socket.io für einen Chat Webapp und ich bekomme den folgenden Fehler zufällig etwa 5 Mal während 24h. Der Node-Prozess wird für immer eingewickelt und er startet sich sofort neu.
Das Problem ist, dass der Neustart von express meine Benutzer aus ihren Räumen wirft und das will niemand.
Der Webserver wird von HAProxy als Proxy verwendet. Es gibt keine Socket-Stabilitätsprobleme, ich verwende nur Websockets und Flashsockets-Transporte. Ich kann dies nicht absichtlich reproduzieren.
Dies ist der Fehler mit Knoten 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
BEARBEITUNG (2013-07-22)
Sowohl der socket.io-Client-Fehler-Handler als auch der Uncaught-Exception-Handler wurden hinzugefügt. Scheint, dass dieser den Fehler abfängt:
process.on('uncaughtException', function (err) {
console.error(err.stack);
console.log("Node NOT Exiting...");
});
Ich vermute also, dass es sich nicht um ein socket.io-Problem handelt, sondern um eine http-Anfrage an einen anderen Server oder eine mysql/redis-Verbindung. Das Problem ist, dass der Fehlerstapel mir nicht hilft, mein Codeproblem zu identifizieren. Hier ist die Log-Ausgabe:
Error: read ECONNRESET
at errnoException (net.js:900:11)
at TCP.onread (net.js:555:19)
Wie kann ich herausfinden, was die Ursache dafür ist? Wie kann ich mehr über den Fehler herausfinden?
Ok, nicht sehr ausführlich, aber hier ist der Stacktrace mit "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] ] } }
Hier stelle ich die Flash-Socket-Policy-Datei bereit:
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)
Kann dies die Ursache sein?
Sie haben es vielleicht schon erraten: Es handelt sich um einen Verbindungsfehler.
"ECONNRESET" bedeutet, dass die andere Seite der TCP-Konversation ihr Ende der Verbindung abrupt geschlossen hat. Dies ist höchstwahrscheinlich auf einen oder mehrere Anwendungsprotokollfehler zurückzuführen. Sie können sich die Protokolle des API-Servers ansehen, um zu sehen, ob er sich über etwas beschwert.
Da Sie aber auch nach einer Möglichkeit suchen, den Fehler zu überprüfen und das Problem möglicherweise zu beheben, sollten Sie einen Blick auf "How to debug a socket hang up error in NodeJS?" werfen, das bei stackoverflow im Zusammenhang mit einer ähnlichen Frage veröffentlicht wurde.
Schnelle und schmutzige Lösung für die Entwicklung:
Verwenden Sie longjohn, erhalten Sie lange Stack Traces, die die asynchronen Operationen enthalten werden.
Saubere und korrekte Lösung: Technisch gesehen, wird in Node jedes Mal, wenn Sie ein `'error'-Ereignis ausgeben und niemand darauf hört, dieses Ereignis geworfen. Damit es nicht auslöst, setzen Sie einen Listener darauf und behandeln es selbst. Auf diese Weise können Sie den Fehler mit mehr Informationen protokollieren.
Um einen Listener für eine Gruppe von Aufrufen zu haben, können Sie domains verwenden und auch andere Fehler während der Laufzeit abfangen. Stellen Sie sicher, dass jede asynchrone Operation, die mit http(Server/Client) zusammenhängt, in einem anderen domain-Kontext ist als die anderen Teile des Codes, die Domain wird automatisch auf die "Fehler"-Ereignisse hören und sie an ihren eigenen Handler weiterleiten. Sie hören also nur auf diesen Handler und erhalten die Fehlerdaten. [Sie erhalten außerdem kostenlos weitere Informationen.(http://nodejs.org/api/all.html#all_additions_to_error_objects)
ÄNDERUNG (2013-07-22)
Wie ich oben geschrieben habe:
"ECONNRESET" bedeutet, dass die andere Seite der TCP-Konversation ihr Ende der Verbindung abrupt geschlossen hat. Dies ist höchstwahrscheinlich auf einen oder mehrere Fehler im Anwendungsprotokoll zurückzuführen. Sie können sich die Protokolle des API-Servers ansehen, um zu sehen, ob er sich über etwas beschwert.
Es könnte auch sein, dass die andere Seite zu bestimmten Zeiten überlastet ist und die Verbindung deshalb einfach abbricht. Ob das der Fall ist, hängt davon ab, mit was Sie sich genau verbinden...
Aber eines ist sicher: Sie haben tatsächlich einen Lesefehler bei Ihrer TCP-Verbindung, der die Ausnahme verursacht. Sie können dies anhand des Fehlercodes erkennen, den Sie in Ihrer Bearbeitung gepostet haben, was dies bestätigt.
Ein einfacher TCP-Server, den ich für die Bereitstellung der Flash-Richtliniendatei hatte, verursachte dies. Ich kann jetzt den Fehler mit einem Handler abfangen:
# 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)
Ich hatte ein ähnliches Problem, bei dem Apps nach einem Upgrade von Node nicht mehr funktionierten. Ich glaube, dass dies auf die Node-Version v0.9.10 zurückgeführt werden kann:
Frühere Versionen haben bei Unterbrechungen durch den Client keinen Fehler gemacht. Eine Unterbrechung der Verbindung vom Client löst in Node den Fehler ECONNRESET aus. Ich glaube, dies ist die beabsichtigte Funktionalität für Node, so dass die Lösung (zumindest für mich) war, den Fehler zu behandeln, die ich glaube, Sie haben in unCaught Ausnahmen. Obwohl ich es in der net.socket Handler behandeln.
Sie können dies demonstrieren:
Erstellen Sie einen einfachen Socket-Server und holen Sie sich Node v0.9.9 und v0.9.10.
require('net')
.createServer( function(socket)
{
// no nothing
})
.listen(21, function()
{
console.log('Socket ON')
})
Starten Sie ihn mit v0.9.9 und versuchen Sie dann, per FTP auf diesen Server zuzugreifen. Ich verwende FTP und Port 21 nur, weil ich unter Windows arbeite und einen FTP-Client, aber keinen Telnet-Client zur Hand habe.
Dann brechen Sie auf der Client-Seite einfach die Verbindung ab. (Ich mache gerade Strg-C)
Sie sollten KEINEN FEHLER sehen, wenn Sie Node v0.9.9 verwenden, und FEHLER, wenn Sie Node v.0.9.10 und höher verwenden.
In der Produktion verwende ich v.0.10. etwas und es gibt immer noch den Fehler. Auch hier denke ich, dass dies beabsichtigt ist und die Lösung ist, den Fehler in Ihrem Code zu behandeln.