web-dev-qa-db-fra.com

Comment puis-je empêcher le blocage de node.js? try-catch ne fonctionne pas

De mon expérience, un serveur php lève une exception dans le journal ou à la fin du serveur, mais node.js se bloque simplement. Entourer mon code d'un try-catch ne fonctionne pas non plus, car tout se fait de manière asynchrone. J'aimerais savoir ce que tous les autres font sur leurs serveurs de production.

134
TiansHUo

D'autres réponses sont vraiment insensées, comme vous pouvez le lire dans les propres documents de Node à l'adresse http://nodejs.org/docs/latest/api/process.html#process_event_uncaughtexception

Si quelqu'un utilise d'autres réponses indiquées, lisez le document sur les nœuds:

Notez que uncaughtException est un mécanisme très grossier pour la gestion des exceptions et peut être supprimé à l'avenir.

PM2

Tout d'abord, je vous recommande fortement d'installer PM2 pour Node.js. PM2 est vraiment efficace pour gérer les pannes et surveiller les applications de nœud, ainsi que pour équilibrer la charge. PM2 démarre immédiatement l'application Node chaque fois qu'elle se bloque, s'arrête pour une raison quelconque ou même lorsque le serveur redémarre. Donc, si un jour, même après avoir géré notre code, l'application se bloque, PM2 peut le redémarrer immédiatement. Pour plus d'informations, Installation et exécution de PM2

Revenons maintenant à notre solution pour empêcher l’application elle-même de se bloquer.

Ainsi, après avoir parcouru le sujet, j'ai finalement trouvé ce que le document Node suggère lui-même:

N'utilisez pas uncaughtException, utilisez plutôt domains avec cluster. Si vous utilisez uncaughtException, redémarrez votre application après chaque exception non gérée!

DOMAINE avec cluster

En réalité, nous envoyons une réponse d'erreur à la demande qui l'a déclenchée, tout en laissant les autres terminer à l'heure normale, et nous arrêtons d'écouter les nouvelles demandes de ce travailleur.

De cette manière, l'utilisation du domaine va de pair avec le module de cluster, car le processus maître peut créer un nouveau travailleur lorsqu'un travailleur rencontre une erreur. Voir le code ci-dessous pour comprendre ce que je veux dire

En utilisant Domain et en nous permettant de séparer notre programme en plusieurs processus de travail utilisant Cluster, nous pouvons réagir de manière plus appropriée et gérer les erreurs avec beaucoup plus de sécurité.

var cluster = require('cluster');
var PORT = +process.env.PORT || 1337;

if(cluster.isMaster) 
{
   cluster.fork();
   cluster.fork();

   cluster.on('disconnect', function(worker) 
   {
       console.error('disconnect!');
       cluster.fork();
   });
} 
else 
{
    var domain = require('domain');
    var server = require('http').createServer(function(req, res) 
    {
        var d = domain.create();
        d.on('error', function(er) 
        {
            //something unexpected occurred
            console.error('error', er.stack);
            try 
            {
               //make sure we close down within 30 seconds
               var killtimer = setTimeout(function() 
               {
                   process.exit(1);
               }, 30000);
               // But don't keep the process open just for that!
               killtimer.unref();
               //stop taking new requests.
               server.close();
               //Let the master know we're dead.  This will trigger a
               //'disconnect' in the cluster master, and then it will fork
               //a new worker.
               cluster.worker.disconnect();

               //send an error to the request that triggered the problem
               res.statusCode = 500;
               res.setHeader('content-type', 'text/plain');
               res.end('Oops, there was a problem!\n');
           } 
           catch (er2) 
           {
              //oh well, not much we can do at this point.
              console.error('Error sending 500!', er2.stack);
           }
       });
    //Because req and res were created before this domain existed,
    //we need to explicitly add them.
    d.add(req);
    d.add(res);
    //Now run the handler function in the domain.
    d.run(function() 
    {
        //You'd put your fancy application logic here.
        handleRequest(req, res);
    });
  });
  server.listen(PORT);
} 

Bien que Domain soit en attente de la dépréciation et soit supprimé, le nouveau remplacement se présente comme indiqué dans la documentation du nœud.

Ce module est en attente de désapprobation. Une fois qu'une API de remplacement a été finalisée, ce module sera totalement obsolète. Les utilisateurs qui doivent absolument disposer des fonctionnalités fournies par les domaines peuvent s’en remettre à eux pour le moment, mais devraient s’attendre à devoir migrer vers une solution différente à l’avenir.

Mais jusqu'à ce que le nouveau remplacement ne soit pas introduit, Domain with Cluster est la seule bonne solution proposée par Node Documentation.

Pour comprendre en profondeur Domain et Cluster lire

 https://nodejs.org/api/domain.html#domain_domain (Stability: 0 - Deprecated)

 https://nodejs.org/api/cluster.html

Merci à @Stanley Luo de nous avoir partagé cette merveilleuse explication détaillée sur les clusters et les domaines.

Cluster & Domaines

116

Je mets ce code juste sous mes instructions require et mes déclarations globales:

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

travaille pour moi. La seule chose que je n'aime pas, c'est que je ne reçois pas autant d'informations que si je laissais tomber la chose.

70
hvgotcodes

Comme mentionné ici , vous trouverez que error.stack fournit un message d'erreur plus complet, tel que le numéro de ligne qui a provoqué l'erreur:

process.on('uncaughtException', function (error) {
   console.log(error.stack);
});
27
Sean Bannister

Essayez supervisor

npm install supervisor
supervisor app.js

Ou vous pouvez installer forever à la place.

Tout ce que cela va faire est de récupérer votre serveur en cas de panne en le redémarrant.

forever peut être utilisé dans le code pour récupérer en douceur tous les processus qui se bloquent.

Les documents forever ont des informations solides sur la gestion des sorties/erreurs par programmation.

12
Raynos

L'utilisation de try-catch peut résoudre les erreurs non détectées, mais dans certaines situations complexes, cela ne fonctionnera pas correctement, comme de capturer une fonction asynchrone. N'oubliez pas que dans Node, tout appel de fonction asynchrone peut contenir une opération susceptible de provoquer le blocage de l'application. 

Utiliser uncaughtException est une solution de contournement, mais il est reconnu comme étant inefficace et sera probablement supprimé dans les futures versions de Node. Ne comptez donc pas dessus.

La solution idéale consiste à utiliser le domaine: http://nodejs.org/api/domain.html

Pour vous assurer que votre application est opérationnelle et que votre serveur est en panne, procédez comme suit:

  1. utiliser un cluster de nœuds pour créer plusieurs processus par cœur Donc, si un processus est mort, un autre processus sera le démarrage automatique. Découvrez: http://nodejs.org/api/cluster.html

  2. utilisez domain pour intercepter une opération asynchrone au lieu d'utiliser try-catch ou non attrapé. Je ne dis pas que tenter-attraper ou non attiré est une mauvaise idée!

  3. utiliser pour toujours/superviseur pour surveiller vos services

  4. ajoutez un démon pour exécuter votre application de nœud: http://upstart.ubuntu.com

j'espère que cela t'aides!

7
Nam Nguyen

Essayez le module de nœud pm2, il est très cohérent et contient une excellente documentation. Gestionnaire de processus de production pour les applications Node.js avec un équilibreur de charge intégré. évitez s'il vous plaît uncaughtException pour ce problème. https://github.com/Unitech/pm2

4
Virendra Rathore

Fonctionne très bien sur restify:

server.on('uncaughtException', function (req, res, route, err) {
  log.info('******* Begin Error *******\n%s\n*******\n%s\n******* End Error *******', route, err.stack);
  if (!res.headersSent) {
    return res.send(500, {ok: false});
  }
  res.write('\n');
  res.end();
});
0
PH Andrade

UncaughtException est "un mécanisme très grossier" (donc vrai) et les domaines sont obsolètes maintenant. Cependant, nous avons encore besoin d'un mécanisme pour détecter les erreurs autour des domaines (logiques). La bibliothèque:

https://github.com/vacuumlabs/yacol

peut vous aider à le faire. Avec un peu d'écriture supplémentaire, vous pouvez avoir la sémantique de domaine Nice tout autour de votre code!

0
Tomas Kulich