Shuping
Shuping

Reputation: 5458

NodeJs catch unhandled error happens in async methods

Originally I would like to ask a question about how to create robuts web server based on Node.js. However, that could be a very large and ambiguous question. So I break it to small and concrete question or chanllenge that I am facing when creating a robuts web server.

So, one of the chanllenge I am facing is how to catch all unhandled errors in Node.js? I want to do this becasue I do not want any unhandled error stops Node.js from running which results in web server down.

The solution comes to mind is to put the server running code block in a try-catch block to catch all unhandled errors. however, this is not working if any error happens from an async method. For example my web server could look like below code:

var fs = require('fs');
var http = require('http');

try {

    // Here is my main web server, it could happen errors by adding
    // more and more modules and functionalities to my server.
    // I need to catch all unhandled errors to prevent server from crashing
    // So, I put my whole server running in a try-catch block, but any error from
    // an async method could not be caught!
    http.createServer(function(req, res) {
        throw Error("An unhandled error happens!");
    }).listen(1234);

}catch (e){
    console.log("An unhandled error caught!")
}

console.log('Server is listening to port 1234');

So, am I on the correct direction of error handling to make sure server no stopping? or there is some other mechanism to make server recover from an error?

Upvotes: 2

Views: 4205

Answers (3)

Gabriel Llamas
Gabriel Llamas

Reputation: 18427

You need to use domains.

One global domain that wraps all the server and one domain per request. If you get an error during initialization the global domain will catch the error, then you can log it, do some clean up tasks and kill the server. If you get an error from the request log it with the highest priority and continue serving other requests. This is how the node.js wants us to write robust web servers.

The major problem is to try to shutdown as graceful as you can. A graceful exit means that when you need to kill the server (from a ctrl-c or sigint or error or whatever) instead of doing a simple process.exit(1) you must clean up resources like closing database connections, closing files, notify someone, etc. You cannot use process.on("exit", ...) because when the handler is called the event loop doesn't work and you cannot perform asynchronous tasks.

Also, if you use workers how do you gracefully shutdown them when the server need to shutdown?

How do you handle express errors?

All these stuff seems pretty complex to implement to always guarantee a graceful shutdown. That's why I did node-grace.

Upvotes: 4

Ivan Vetrov
Ivan Vetrov

Reputation: 61

Use try/catch inside your callback functions:

var fs = require('fs');
var http = require('http');

try {
    http.createServer(function(req, res) {
        try{
            // some code trowing erors
        }catch(e){
             console.log("error: " + e);
        }
}).listen(1234);

}catch (e){
    console.log("An unhandled error caught!")
}

console.log('Server is listening to port 1234');

Why that happens? Async http callbacks don't run at the same tick as code which sets up the http server callback function (moreover that function is called every time your server gets request). Try your self:

 try{
      throw Error("An unhandled error happens!");
 }catch(e){
     console.log(e)
 }

and:

 try{
     process.nextTick(function(){
        throw Error("An unhandled error happens!")
     });
 }
 catch(e){
     console.log(e)
 }

Upvotes: 2

robertklep
robertklep

Reputation: 203304

If using Express is an option for you, I would suggest using that instead of the rather low-level http module. With Express, you can handle errors nicely:

var express = require('express');
var app     = express();

app.get('/', function(req, res) {
  throw Error("An unhandled error happens!");
});

app.use(function(err, req, res, next) {
  console.log('error', err);
  res.send(500); // send a proper HTTP 500 message back to the client
});

app.listen(1234);

console.log('Server is listening to port 1234');

Otherwise, take a look at the domain module of Node

Upvotes: 1

Related Questions