node.jsexceptionserverside-javascript

Node.js Best Practice Exception Handling


I just started trying out node.js a few days ago. I've realized that the Node is terminated whenever I have an unhandled exception in my program. This is different than the normal server container that I have been exposed to where only the Worker Thread dies when unhandled exceptions occur and the container would still be able to receive the request. This raises a few questions:

I would appreciate any pointer/article that would show me the common best practices for handling uncaught exceptions in node.js


Solution

  • Update: Joyent now has their own guide. The following information is more of a summary:

    Safely "throwing" errors

    Ideally we'd like to avoid uncaught errors as much as possible, as such, instead of literally throwing the error, we can instead safely "throw" the error using one of the following methods depending on our code architecture:

    Safely "catching" errors

    Sometimes though, there may still be code that throws an error somewhere which can lead to an uncaught exception and a potential crash of our application if we don't catch it safely. Depending on our code architecture we can use one of the following methods to catch it:

    If you do want to work with try..catch in conjunction with asynchronous code, when running Node 7.4 or higher you can use async/await natively to write your asynchronous functions.

    Another thing to be careful about with `try...catch` is the risk of wrapping your completion callback inside the `try` statement like so:
    
        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)
            }
        }
    
        var continueElsewhere = function(err, result){
                throw new Error('elsewhere has failed')
        }
    
        try {
                divide(4, 2, continueElsewhere)
                // ^ the execution of divide, and the execution of 
                //   continueElsewhere will be inside the try statement
        }
        catch (err) {
                console.log(err.stack)
                // ^ will output the "unexpected" result of: elsewhere has failed
        }
    
    This gotcha is very easy to do as your code becomes more complex. As such, it is best to either use domains or to return errors to avoid (1) uncaught exceptions in asynchronous code (2) the try catch catching execution that you don't want it to. In languages that allow for proper threading instead of JavaScript's asynchronous event-machine style, this is less of an issue.