Node JS - Error Handling

//English

Hi Guys, today I want to talk about the Error Handling on NodeJS, so far there's no way to handle the
errors properly on Node. There are certain techniques, I'm going to touch on a couple of them in this post, but these techniques are unstable for now. But they still work, maybe in future releases Joyent will change these specifications or at least some of them.

<!-- Bad way or the way we used to do it... -->

Usually we catch the error on the process of our application, we do something like this:


1
2
3
process.on('uncaughtException',function(err){
    //Let's handle the error...
})

But, what are we doing wrong? We are following what Joyent says, If something unexpected happens, we should catch it and handle the error properly...The problem here is that we are catching the error at the process level, so if you have some async process running in background and one of them throws an error, it will break the entire application. It's really hard to recover from an error if we handle it this way.

<!-- A better approach but still not the appropiate -->

Recently Node has introduced the feature: Domains. Domains are used to split our application and handle them properly, so in this case if you want to run 2 different servers, for instance, you can create a domain for each and the scope will be isolated; this means that if one of them throws an error, you could handle it at domain level, not at the process level.

But, you could say, what is the difference between handling the errors at domain or process level? Well by themselves, the domains don't do so much...it will finish the application like if you were handling the errors at the process level; what domains do is bring us a better way to isolate the errors and finish the process in a better way, without any memory leaking or something like that.

The following is an example of how to deal with the errors using domains:


1
2
3
4
5
6
7
8
9
var d = require('domain').create();

d.on('error',function(err){
    //Let's handle the error...
});

d.run(function(){
    //Let's execute the application...
});

<!-- Let's see how we should handle the errors... -->

We have seen 2 different ways so far of how to handle errors in Node, but none of them have been the most appropriate. What we should do is use a combination of domains and clusters and what is it? basically you add another layer to your program, something like this:


A worker is a fork of a cluster, but, what is it? Basically node runs in a single thread so to take advantage of multi-core systems, Node is introducing the clusters, which will be "workers". Ideally you should have the same number of workers as cores in your system. These workers will be a spawn process which help the main process to handle the load.

The 'workers' will die until they get disconnected, but the difference with the domains is that if one worker got disconnected, your application won't be terminated! But, how can I keep working? Easy! As you may know, Node works with something called the Event Loop, everything in Node dispatches events, we just need to catch that Event and start our worker again...something like this:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var domain = require('domain'),
    cluster = require('cluster');

if(cluster.isMaster){
    //Main Thread...here you usually create the workers, this is all the job for the main Thread, create workers...and the workers will do the heavy stuff
    cluster.fork();//This is how you create a worker

    //Now let's detect if a worker got disconnected
    cluster.on('disconnect',function(worker){
        //This is where you put your logic for restarting the application...
        cluster.fork();//Let's create another worker...
    });
}else{
    //this will be the job done by the workers...usually you create domains, to detect if something unexpected happen, and manage correctly the situation.

    var d = domain.create();
    
    d.on('error',function(err){
        //This what you do to handle the error properly:

        //Let's terminate the process in case something unexpected happen after this point (usually errors with memory or something like this) with 30s will be enough to see if the system can recover itself
        var killprocess = setTimeout(function(){
            process.exit(1);
        },30000);

        //Don't keep the application running just for this timeout
        killprocess.unref();

        //Disconnect/Kill this worker, something unexpected happen, let's restart...
        cluster.worker.disconnect();


        //Let's close the remaining processes

    });

    d.run(function(){
        //Here you put your logic, the one that will be executed.
    });
}

As you may see, your code is getting a little complex, but that's not entirely true. You can put your logic in a separate file and require it on the run function and execute it (That's why I love Node).

If you follow an architecture like this, then, for sure, your code won't fail again or at least if it fails, it restarts by itself or in case that this can't be done, it will stop your program more properly. In other words we put a shield to our code, to protect itself in case something unexpected happens. we give it a second chance to be executed if something goes wrong.

<!-- Example -->

You can see some examples about the 3 options that we discussed before, if you go to this workspace

<!-- Summary -->

There are many ways to handle the errors on Node, which is the better? that depends on what you are doing...maybe this could be too complex for a scenario where you do something easy, like math functions or something like this (Let's use the first option for this situation), but, if you are doing something complex, like write/read files, then you should create a domain without the clusters. But if you want to set up a server, you definitely should use the last option, not just to handle the errors but to take advantage of the multi-core systems (I'm going to write something about it in future posts).

Well guys that's it, if you have doubts or questions, please leave your comments in the proper section.

//Español

Muy pronto...

Comments

Popular posts from this blog

Juego de Gato Usando HTML, JavaScript y CSS

AfterEffects - Quitar el Fondo de un Video Forma 1: KeyLight

Crear un nuevo Libro de Excel con VBA ES