744 votos

Node.js Mejores Prácticas De Manejo De Excepciones

Acabo de empezar a probar node.js hace un par de días. Me he dado cuenta de que el Nodo se termina cada vez que tengo una excepción no controlada en mi programa. Esto es diferente de la normal servidor de contenedor que he estado expuesto a donde sólo el Subproceso de muere cuando las excepciones no controladas y el contenedor todavía podría ser capaz de recibir la solicitud. Esto plantea un par de preguntas:

  • Es process.on('uncaughtException') la única manera efectiva de guardia en contra de ella?
  • Se process.on('uncaughtException') de la captura de la excepción no controlada durante la ejecución de los procesos asincrónicos así?
  • Hay un módulo que ya está construido (como el envío de correo electrónico o por escrito en un archivo que podía aprovechar en el caso de uncaught excepción?

Agradecería cualquier puntero/el artículo que me mostrara el común de las mejores prácticas para el manejo de excepciones en uncaught node.js

722voto

balupton Puntos 17805

Actualización: Joyent ahora tiene su propia guía mencionados en esta respuesta. La siguiente información es más que un resumen:

De forma segura "tirar" de los errores

Idealmente, nos gustaría evitar uncaught errores en la medida de lo posible, como tales, en lugar de literalmente, tirar el error, por el contrario, podemos con seguridad "lanzar" el error usando uno de los siguientes métodos, dependiendo de nuestro código de arquitectura:

  • Para el código sincrónico, si ocurre un error, el error:

    // Define divider as a syncrhonous function
    var divideSync = function(x,y) {
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by returning it
            return new Error("Can't divide by zero");
        }
        else {
            // no error occured, continue on
            return x/y;
        }
    };
    
    // Divide 4/2
    var result;
    result = divideSync(4,2);
    // did an error occur?
    if ( result instanceof Error ) {
        // handle the error safely
        console.log('4/2=err', result);
    }
    else {
        // no error occured, continue on
        console.log('4/2='+result);
    }
    
    // Divide 4/0
    result = divideSync(4,0);
    // did an error occur?
    if ( result instanceof Error ) {
        // handle the error safely
        console.log('4/0=err', result);
    }
    else {
        // no error occured, continue on
        console.log('4/0='+result);
    }
    
  • Para la devolución de llamada (es decir. asincrónico) del código, el primer argumento de la devolución de llamada, err, si ocurre un error err es el error, si un error de que no suceda, a continuación, err es null. Cualquier otro argumento siga las err argumento:

    var divide = function(x,y,next) {
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by calling the completion callback
            // with the first argument being the error
            next(new Error("Can't divide by zero"));
        }
        else {
            // no error occured, continue on
            next(null, x/y);
        }
    };
    
    divide(4,2,function(err,result){
        // did an error occur?
        if ( err ) {
            // handle the error safely
            console.log('4/2=err', err);
        }
        else {
            // no error occured, continue on
            console.log('4/2='+result);
        }
    });
    
    divide(4,0,function(err,result){
        // did an error occur?
        if ( err ) {
            // handle the error safely
            console.log('4/0=err', err);
        }
        else {
            // no error occured, continue on
            console.log('4/0='+result);
        }
    });
    
  • Para agitada código, donde el error puede ocurrir en cualquier lugar, en lugar de tirar el error, el fuego la error evento lugar:

    // Definite our Divider Event Emitter
    var events = require('events');
    var Divider = function(){
        events.EventEmitter.call(this);
    };  require('util').inherits(Divider, events.EventEmitter);
    
    // Add the divide function
    Divider.prototype.divide = function(x,y){
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by emitting it
            var err = new Error("Can't divide by zero");
            this.emit('error', err);
        }
        else {
            // no error occured, continue on
            this.emit('divided', x, y, x/y);
        }
    
        // Chain
        return this;
    };
    
    // Create our divider and listen for errors
    var divider = new Divider();
    divider.on('error', function(err){
        // handle the error safely
        console.log(err);
    });
    divider.on('divided', function(x,y,result){
        console.log(x+'/'+y+'='+result);
    });
    
    // Divide
    divider.divide(4,2).divide(4,0);
    

De forma segura "de la captura de los" errores

A veces, sin embargo, puede todavía ser código que produce un error en alguna parte que puede conducir a una excepción no capturada y potenciales de accidentes de nuestra aplicación si no captamos de manera segura. Dependiendo de nuestro código de la arquitectura podemos utilizar uno de los siguientes métodos de captura:

  • Cuando sabemos dónde se produce el error, se puede envolver esa sección en un node.js dominio

    var d = require('domain').create();
    d.on('error', function(err){
        // handle the error safely
        console.log(err);
    });
    
    // catch the uncaught errors in this asynchronous or synchronous code block
    d.run(function(){
        // the asynchronous or synchronous code that we want to catch thrown errors on
        var err = new Error('example');
        throw err;
    });
    
  • Si sabemos dónde se produce el error es de código sincrónico, y que por cualquier razón no se puede utilizar dominios (quizás versión antigua de nodo), podemos utilizar el try catch declaración:

    // catch the uncaught errors in this synchronous code block
    // try catch statements only work on synchronous code
    try {
        // the synchronous code that we want to catch thrown errors on
        var err = new Error('example');
        throw err;
    } catch (err) {
        // handle the error safely
        console.log(err);
    }
    
  • Sin embargo, todavía puede haber un caso en el que dicho error sucede en un lugar que no estaba envuelto en un dominio o un try catch declaración, en cuyo caso para hacer que nuestra aplicación no falla, podemos usar la uncaughtException oyente (sin embargo, si lo puede poner la aplicación en un estado desconocido):

    // catch the uncaught errors that weren't wrapped in a domain or try catch statement
    // do not use this in modules, but only in applications, as otherwise we could have multiple of these bound
    process.on('uncaughtException', function(err) {
        // handle the error safely
        console.log(err);
    });
    
    // the asynchronous or synchronous code that emits the otherwise uncaught error
    var err = new Error('example');
    throw err;
    

29voto

nponeccop Puntos 8111

Usted puede coger uncaught excepciones, pero es de uso limitado. Ver http://debuggable.com/posts/node-js-dealing-with-uncaught-exceptions:4c933d54-1428-443c-928d-4e1ecbdd56cb

monit, forever o upstart puede ser utilizado para reiniciar el nodo de proceso cuando se bloquea. Un cierre es mejor que te puede pasar (por ejemplo, guardar todos los datos en memoria en uncaught exception handler).

13voto

B T Puntos 4868

nodejs dominios es la más actualizada de la manera de manejar los errores en nodejs. Los dominios pueden capturar el error/otros eventos así como tradicionalmente los objetos lanzados. Dominios también proporciona funcionalidad para el manejo de las devoluciones de llamada con un error del pasado como primer argumento a través de la intercepción de método.

Como con el normal try/catch-estilo de manejo de errores, es generalmente mejor para lanzar los errores cuando se producen, y el bloque de áreas donde se desea aislar los errores que se afecte el resto del código. El camino para "bloquear" estas áreas son : llamar a domain.run con una función como un bloque aislado de código.

En el código sincrónico, el de arriba es suficiente - cuando ocurre un error que cualquiera deje de ser lanzado a través de, o de coger y manejar allí, volviendo todos los datos que necesite para volver.

try {  
  //something
} catch(e) {
  // handle data reversion
  // probably log too
}

Cuando sucede el error asíncrono, devolución de llamada, usted necesita ser capaz de manejar por completo la reversión de datos (estado compartido de datos externos como bases de datos, etc.). O hay que configurar algo para indicar que una excepción que ha sucedido - donde quiera que usted se preocupa de que la bandera, usted tiene que esperar la llamada de vuelta a completar.

var err = null;
var d = require('domain').create();
d.on('error', function(e) {
  err = e;
  // any additional error handling
}
d.run(function() { Fiber(function() {
  // do stuff
  var future = somethingAsynchronous();
  // more stuff

  future.wait(); // here we care about the error
  if(err != null) {
    // handle data reversion
    // probably log too
  }

})});

Algunos de los que el código anterior es feo, pero usted puede crear patrones para hacer más guapa, por ejemplo:

var specialDomain = specialDomain(function() {
  // do stuff
  var future = somethingAsynchronous();
  // more stuff

  future.wait(); // here we care about the error
  if(specialDomain.error()) {
    // handle data reversion
    // probably log too
  } 
}, function() { // "catch"
  // any additional error handling
});

ACTUALIZACIÓN (2013-09):

Anteriormente, yo uso un futuro que implica fibras de la semántica, la cual permite esperar en el futuro en-línea. Esta realidad permite el uso tradicional de los bloques try-catch para todo , lo que me parece ser el mejor camino a seguir. Sin embargo, no siempre se pueden hacer esto (es decir, en el navegador)...

También hay futuros que no requieren de las fibras de la semántica (que, a continuación, trabajar con normalidad, browsery JavaScript). Estos pueden ser llamados futuros, promesas, o deferreds (voy a referir a los futuros, a partir de aquí). Llano-viejo-JavaScript futuros de las bibliotecas de permitir que los errores se propagan entre futuros. Sólo algunas de estas bibliotecas permiten a cualquier lanzado el futuro a ser manejados correctamente, así que ten cuidado.

Un ejemplo:

returnsAFuture().then(function() {
  console.log('1')
  return doSomething() // also returns a future

}).then(function() {
  console.log('2')
  throw Error("oops an error was thrown")

}).then(function() {
  console.log('3')

}).catch(function(exception) {
  console.log('handler')
  // handle the exception
}).done()

Esto imita normal try-catch, aunque las piezas son asincrónicas. Sería de impresión:

1
2
handler

Tenga en cuenta que no print '3', porque se produce una excepción que interrumpe el flujo.

Eche un vistazo a estas bibliotecas:

Tenga en cuenta que no he encontrado muchas otras bibliotecas de estos que manejan correctamente lanzado excepciones. jQuery diferido, por ejemplo, no se - el "error" controlador nunca tendrían la excepción de un 'entonces' controlador, que en mi opinión es un interruptor.

11voto

Simon Maynard Puntos 81

Hace poco escribí sobre esto en http://snmaynard.com/2012/12/21/node-error-handling/. Una nueva característica de nodo en la versión 0.8 es de dominios y le permiten combinar todas las formas de manejo de errores en uno fácil de gestionar de forma. Usted puede leer acerca de ellos en mi post.

También puedes usar algo como Bugsnag para el seguimiento de su uncaught excepciones y será notificada a través de correo electrónico, sala de chat o de tener un billete creado por una excepción no detectada (yo soy el co-fundador de Bugsnag).

4voto

Yuriy Nemtsov Puntos 1430

Es posible que desee leer Manejo de Errores en Node.js.
Es un muy completo documento publicado por Joyent.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X