Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I prevent node.js from crashing? try-catch doesn't work

People also ask

What are the problems with node js?

Problems occurring in Node. js application deployments can have a range of symptoms, but can generally be categorized into the following: Uncaught exception or error event in JavaScript code. Excessive memory usage, which may result in an out-of-memory error.

Is it good to use try catch in node JS?

It means that you should try to avoid try/catch in hot code paths. Logic/business errors in Node are usually handled with error-first callback patterns (or Promises, or similar). Generally you'd only use try/catch if you expect programmer errors (ie. bugs), and other patterns for errors you expect.


PM2

First of all, I would highly recommend installing PM2 for Node.js. PM2 is really great at handling crash and monitoring Node apps as well as load balancing. PM2 immediately starts the Node app whenever it crashes, stops for any reason or even when server restarts. So, if someday even after managing our code, app crashes, PM2 can restart it immediately. For more info, Installing and Running PM2

Other answers are really insane as you can read at Node's own documents at http://nodejs.org/docs/latest/api/process.html#process_event_uncaughtexception

If someone is using other stated answers read Node Docs:

Note that uncaughtException is a very crude mechanism for exception handling and may be removed in the future

Now coming back to our solution to preventing the app itself from crashing.

So after going through I finally came up with what Node document itself suggests:

Don't use uncaughtException, use domains with cluster instead. If you do use uncaughtException, restart your application after every unhandled exception!

DOMAIN with Cluster

What we actually do is send an error response to the request that triggered the error, while letting the others finish in their normal time, and stop listening for new requests in that worker.

In this way, domain usage goes hand-in-hand with the cluster module, since the master process can fork a new worker when a worker encounters an error. See the code below to understand what I mean

By using Domain, and the resilience of separating our program into multiple worker processes using Cluster, we can react more appropriately, and handle errors with much greater safety.

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);
} 

Though Domain is pending deprecation and will be removed as the new replacement comes as stated in Node's Documentation

This module is pending deprecation. Once a replacement API has been finalized, this module will be fully deprecated. Users who absolutely must have the functionality that domains provide may rely on it for the time being but should expect to have to migrate to a different solution in the future.

But until the new replacement is not introduced, Domain with Cluster is the only good solution what Node Documentation suggests.

For in-depth understanding Domain and Cluster read

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

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

Thanks to @Stanley Luo for sharing us this wonderful in-depth explanation on Cluster and Domains

Cluster & Domains


I put this code right under my require statements and global declarations:

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

works for me. the only thing i don't like about it is I don't get as much info as I would if I just let the thing crash.


As mentioned here you'll find error.stack provides a more complete error message such as the line number that caused the error:

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

Try supervisor

npm install supervisor
supervisor app.js

Or you can install forever instead.

All this will do is recover your server when it crashes by restarting it.

forever can be used within the code to gracefully recover any processes that crash.

The forever docs have solid information on exit/error handling programmatically.


Using try-catch may solve the uncaught errors, but in some complex situations, it won't do the job right such as catching async function. Remember that in Node, any async function calls can contain a potential app crashing operation.

Using uncaughtException is a workaround but it is recognized as inefficient and is likely to be removed in the future versions of Node, so don't count on it.

Ideal solution is to use domain: http://nodejs.org/api/domain.html

To make sure your app is up and running even your server crashed, use the following steps:

  1. use node cluster to fork multiple process per core. So if one process died, another process will be auto boot up. Check out: http://nodejs.org/api/cluster.html

  2. use domain to catch async operation instead of using try-catch or uncaught. I'm not saying that try-catch or uncaught is bad thought!

  3. use forever/supervisor to monitor your services

  4. add daemon to run your node app: http://upstart.ubuntu.com

hope this helps!