67 votes

Ne fait pas sortir node.js en cas d'erreur

Je suis en train de travailler sur un websocket orienté node.js en utilisant le serveur de Socket.IO. J'ai remarqué un bug où certains navigateurs ne suivent pas la bonne connexion au serveur, et le code n'est pas écrit pour gérer harmonieusement, et en bref, il appelle une méthode d'un objet qui n'a jamais été mis en place, tuant ainsi le serveur en raison d'une erreur.

Mon souci n'est pas avec le bug en particulier, mais le fait que lorsque ces erreurs se produisent, le serveur tombe en panne. Est-ce que je peux faire au niveau mondial dans le nœud de faire en sorte que si une erreur se produit il vous suffit de vous connecter à un message, peut-être tuer l'événement, mais le processus serveur va continuer à courir?

Je ne veux pas que d'autres utilisateurs les connexions à l'aller, grâce à un habile utilisateur en exploitant une erreur non interceptée dans un grand inclus code.

79voto

Ivo Wetzel Points 27802

Vous pouvez connecter un écouteur à l' `uncaughtException" l'événement de l'objet de processus.

Code de l' Node.js référence de l'API (c'est le second élément sous le "processus"):

process.on('uncaughtException', function (err) {
  console.log('Caught exception: ' + err);
});

setTimeout(function () {
  console.log('This will still run.');
}, 500);

// Intentionally cause an exception, but don't catch it.
nonexistentFunc();
console.log('This will not run.');

Tout ce que vous avez à faire maintenant est de vous connecter ou de faire quelque chose avec elle, dans le cas où vous savez dans quelles circonstances le bug se produit, vous devez soumettre un rapport de bogue sur au Socket.IO page GitHub:
https://github.com/LearnBoost/Socket.IO-node/issues

33voto

Rudolf Meijering Points 793

À l'aide de uncaughtException est une très mauvaise idée.

La meilleure alternative est d'utiliser des domaines dans Node.js 0.8. Si vous êtes sur une version antérieure de Node.js utilisez plutôt pour toujours à redémarrer votre processus ou encore mieux utiliser le nœud de cluster pour frayer les multiples processus de travail et de redémarrer un travailleur sur l'éventualité d'une uncaughtException.

De: http://nodejs.org/api/process.html#process_event_uncaughtexception

Notez que uncaughtException est très brut mécanisme d'exception la manipulation et peut être supprimée dans le futur.

Ne l'utilisez pas, au lieu d'utiliser des domaines. Si vous ne l'utilisez, redémarrez votre application après chaque exception non gérée!

Ne l'utilisez pas comme les node.js l'équivalent de on Error Resume Next. Un exception non gérée signifie que votre application - et, par extension, node.js lui - même, est dans un état indéfini. Aveuglément la reprise signifie quoi que ce soit pourrait se produire.

Songer à reprendre en lui tirant le cordon d'alimentation lorsque vous mettez à niveau votre système. Neuf fois sur dix, il ne se passe rien - mais le 10e temps, votre système est le buste.

Vous avez été averti.

6voto

user1334007 Points 1088

J'ai juste fait un tas de recherches dans ce domaine (voir ici, ici, ici, et ici) et la réponse à votre question est que le Nœud ne vous permettra pas d'en écrire un gestionnaire d'erreur, qui va attraper chaque scénario d'erreur qui pourraient survenir dans votre système.

Certains cadres comme express vous permettra d'attraper certains types d'erreurs (quand une méthode asynchrone retourne un objet d'erreur), mais il existe d'autres conditions que vous ne pouvez pas attraper avec un gestionnaire d'erreur. C'est une limitation (à mon avis) de Nœud et, éventuellement, inhérente à la programmation asynchrone en général.

Par exemple, disons que vous avez les éléments suivants express gestionnaire:

app.get("/test", function(req, res, next) {
    require("fs").readFile("/some/file", function(err, data) {
        if(err)
            next(err);
        else
            res.send("yay");
    });
});

Disons que le fichier "certains de/fichier" n'existent pas réellement. Dans ce cas, fs.readFile retournera un message d'erreur comme premier argument de la méthode de rappel. Si vous cochez la case pour que et faire ensuite(err) lorsque cela se produit, la valeur par défaut express gestionnaire d'erreur va prendre le relais et faire ce que vous en faites, par exemple, de retour de 500 à l'utilisateur). C'est une manière élégante pour gérer une erreur. Bien sûr, si vous oubliez de l'appel suivant(err), il ne fonctionne pas.

Donc, c'est la condition d'erreur qu'un gestionnaire peut traiter avec, toutefois envisager un autre cas:

app.get("/test", function(req, res, next) {
    require("fs").readFile("/some/file", function(err, data) {
        if(err)
            next(err);
        else {
            nullObject.someMethod(); //throws a null reference exception
            res.send("yay");
        }
    });
});

Dans ce cas, il y a un bug si votre code qui vous permet d'appeler une méthode sur un objet null. Ici, une exception sera levée, il ne sera pas pris par le gestionnaire d'erreurs globales, et votre nœud de l'application va se terminer. Tous les clients requêtes en cours d'exécution sur ce service permettra d'obtenir soudainement déconnecté avec aucune explication. Pas très gracieux de gestion d'erreur de scénario.

Il n'existe actuellement pas de gestionnaire d'erreurs globales de la fonctionnalité dans le Nœud pour gérer ce cas. Vous ne pouvez pas mettre un géant try/catch autour de tous expresse de votre part des gestionnaires parce que le temps de votre asyn de rappel s'exécute, ceux try/captures sont plus étendue. C'est juste la nature de code asynchrone, il rompt le try/catch erreur de manipulation de paradigme.

Autant que je sache, votre seul recours est ici de mettre try/captures autour de la machine synchrone parties de votre code à l'intérieur de chacune de vos async rappels, quelque chose comme ceci:

app.get("/test", function(req, res, next) {
    require("fs").readFile("/some/file", function(err, data) {
        if(err) {
            next(err);
        }
        else {
            try {
                nullObject.someMethod(); //throws a null reference exception
                res.send("yay");
            }
            catch(e) {
                res.send(500);
            }
        }
    });
});

Qui va le faire pour quelque méchante code, en particulier une fois que vous commencer à entrer dans imbriqués les appels asynchrones.

Certaines personnes pensent que ce Nœud ne dans ces cas (qui est, mourir) est la bonne chose à faire parce que votre système est dans un état incohérent et vous n'avez pas d'autre option. Je suis en désaccord avec ce raisonnement, mais je ne rentrerai pas dans un débat philosophique à ce sujet. Le point est que, avec le Noeud, votre seule option est d'espérer que votre couverture de test est assez bon pour que cela n'arrive pas. Vous pouvez mettre quelque chose comme upstart ou supervisord en place pour redémarrer votre application quand elle descend, mais c'est tout simplement l'atténuation du problème, pas une solution.

Node.js est actuellement instable fonctionnalité appelée domaines qui semble aborder cette question, bien que je ne sais pas beaucoup sur elle.

2voto

Dean Rather Points 7856

Je viens de mettre ensemble une classe qui est à l'écoute pour les exceptions non gérées, et quand il voit un il:

  • imprime la trace de la pile de la console
  • il enregistre dans son propre fichier de log
  • e-mails que vous la trace de la pile
  • redémarre le serveur (ou le tue, à vous de voir)

Il faudra un peu de peaufinage pour votre application que je n'ai pas générique, mais c'est seulement quelques lignes, et c'est peut être ce que vous cherchez!

Check it out!

1voto

KTys Points 90

A eu un problème similaire. Ivo réponse est bonne. Mais comment peut-on attraper une erreur dans une boucle et continuer?

var folder='/anyFolder';
fs.readdir(folder, function(err,files){
    for(var i=0; i<files.length; i++){
        var stats = fs.statSync(folder+'/'+files[i]);
    }
});

Ici, fs.statSynch renvoie une erreur (contre un fichier caché dans Windows, qui barfs je ne sais pas pourquoi). L'erreur peut être pris par le processus.sur(...) la tour, mais la boucle s'arrête.

J'ai essayé d'ajouter un gestionnaire directement:

var stats = fs.statSync(folder+'/'+files[i]).on('error',function(err){console.log(err);});

Cela ne fonctionne pas non plus.

L'ajout d'un try/catch autour de la remise en question de fs.statSynch() était la meilleure solution pour moi:

var stats;
try{
    stats = fs.statSync(path);
}catch(err){console.log(err);}

Elle a permis ensuite le correctif de code (un propre chemin var de fichier et de dossier).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X