J'exécute une application Express js avec socket.io pour une application web de chat. et je reçois l'erreur suivante de manière aléatoire environ 5 fois pendant 24h. Le processus node est enveloppé dans une éternité et il redémarre immédiatement. redémarre immédiatement.
Le problème, c'est que le redémarrage de l'express fait sortir mes utilisateurs de leurs chambres. et personne ne veut ça.
Le serveur web est mandaté par HAProxy. Il n'y a pas de problème de stabilité des sockets, j'utilise simplement les transports websockets et flashsockets. Je ne peux pas reproduire ce problème volontairement.
C'est l'erreur avec le nœud 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
EDIT (2013-07-22)
Ajouté le gestionnaire d'erreur client socket.io et le gestionnaire d'exception non capturée. Il semble que ce dernier attrape l'erreur :
process.on('uncaughtException', function (err) {
console.error(err.stack);
console.log("Node NOT Exiting...");
});
Je soupçonne donc qu'il ne s'agit pas d'un problème de socket.io mais d'une requête http vers un autre serveur que je fais ou d'une connexion mysql/redis. Le problème est que la pile d’erreurs ne m’aide pas à identifier mon problème de code. Voici la sortie du journal :
Error: read ECONNRESET
at errnoException (net.js:900:11)
at TCP.onread (net.js:555:19)
Comment puis-je savoir ce qui cause ce problème ? Comment puis-je obtenir plus d'informations sur cette erreur ?
Ok, ce n'est pas très explicite mais voici le suivi de pile avec "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] ] } }
Ici je sers le fichier de politique de 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)
Cela peut-il être la cause ?
Vous l'avez peut-être déjà deviné : il s'agit d'une erreur de connexion.
"ECONNRESET" signifie que l'autre partie de la conversation TCP a brusquement fermé sa partie de la connexion. Cela est très probablement dû à une ou plusieurs erreurs de protocole d'application. Vous pouvez consulter les journaux du serveur API pour voir s'il se plaint de quelque chose.
Mais puisque vous cherchez également un moyen de vérifier l'erreur et éventuellement de déboguer le problème, vous devriez jeter un coup d'œil à " ;How to debug a socket hang up error in NodeJS ?" qui a été publié sur stackoverflow en relation avec une question similaire.
Solution rapide et sale pour le développement :
Utilisez longjohn, vous obtiendrez de longues traces de pile qui contiendront les opérations asynchrones.
Solution propre et correcte : Techniquement, dans node, lorsque vous émettez un événement
'error'
et que personne ne l'écoute, il sera lancé. Pour qu'il ne soit pas lancé, mettez un écouteur dessus et gérez-le vous-même. De cette façon, vous pouvez enregistrer l'erreur avec plus d'informations.
Pour avoir un écouteur pour un groupe d'appels, vous pouvez utiliser domains et aussi attraper d'autres erreurs à l'exécution. Assurez-vous que chaque opération asynchrone liée à http(Server/Client) se trouve dans un contexte domain différent de celui des autres parties du code, le domaine écoutera automatiquement les événements error
et les propagera vers son propre gestionnaire. Ainsi, vous n'écoutez que ce gestionnaire et obtenez les données d'erreur. (Vous obtenez également plus d'informations gratuitement) (http://nodejs.org/api/all.html#all_additions_to_error_objects)
MISE À JOUR (2013-07-22)
Comme je l'ai écrit ci-dessus :
"ECONNRESET" signifie que l'autre côté de la conversation TCP a brusquement fermé sa fin de connexion. Cela est très probablement dû à une ou plusieurs erreurs de protocole d'application. Vous pouvez consulter les journaux du serveur API pour voir s'il se plaint de quelque chose.
Ce qui pourrait également être le cas : à des moments aléatoires, l'autre côté est surchargé et tue simplement la connexion en conséquence. Si c’est le cas, cela dépend de ce à quoi vous vous connectez exactement...
Mais une chose est sûre : vous avez effectivement une erreur de lecture sur votre connexion TCP qui provoque l'exception. Vous pouvez le constater en regardant le code d'erreur que vous avez posté dans votre édition, ce qui le confirme.
Un simple serveur tcp que j'avais pour servir le fichier de stratégie flash était à l'origine de ce problème. Je peux maintenant attraper l'erreur en utilisant un gestionnaire :
# 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)
J'ai eu un problème similaire où les applications ont commencé à se tromper après une mise à jour de Node. Je pense que cela peut être retracé jusqu'à la version v0.9.10 de Node cet article :
Les versions précédentes ne se trompaient pas sur les interruptions du client. Une interruption de la connexion depuis le client génère l'erreur ECONNRESET dans Node. Je pense qu'il s'agit d'une fonctionnalité prévue pour Node, donc la solution (du moins pour moi) était de gérer l'erreur, ce que vous avez fait, je pense, dans les exceptions unCaught. Bien que je la gère dans le handler net.socket.
Vous pouvez le démontrer :
Faites un simple serveur de socket et obtenez Node v0.9.9 et v0.9.10.
require('net')
.createServer( function(socket)
{
// no nothing
})
.listen(21, function()
{
console.log('Socket ON')
})
Démarrez-le en utilisant la v0.9.9 et essayez ensuite d'accéder par FTP à ce serveur. J'utilise FTP et le port 21 uniquement parce que je suis sous Windows et que j'ai un client FTP, mais pas de client telnet à portée de main.
Ensuite, du côté client, il suffit de rompre la connexion. (Je fais simplement Ctrl-C).
Vous ne devriez voir AUCUNE ERREUR en utilisant Node v0.9.9, et ERREUR en utilisant Node v.0.9.10 et plus.
En production, j'utilise v.0.10. quelque chose et cela donne toujours l'erreur. Encore une fois, je pense que c'est voulu et la solution est de gérer l'erreur dans votre code.