11

The domain built-in module will be deprecated:

Stability: 0 - Deprecated

This module is pending deprecation. Once a replacement API has been finalized, this module will be fully deprecated. Most end users should not have cause to use this module. 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.

According to this, they don't really recommend a solution currently. But how to implement a functionality which is similar to the below one:

var d = require('domain').create();
d.on('error', function(err) {
  console.log(err);
});
d.run(function() {
  setTimeout(function () {
     throw new Error("Something went really wrong in async code.");
  }, 1000);
});

So, this handles the errors thrown from async stuff, but the domain module is deprecated.

How to migrate this code to something better?


My use-case is that I'm writing a library which accepts a function as input and it runs the function and displays the result (actually, you can think at it as unit-testing library):

myLib.it("should do something", function (done) {
   setTimeout(function () {
        // Some async code
        // ...
        // But here an error is thrown
        throw new Error("dummy");
   }, 1000);
});

Obviously, I don't want to crash the process in this case but I do want to show a nice error (so basically catching the error in this function).

Currently in the library I do:

var err = null;
try {
   fn(callback);
} catch (e) {
   err = e;
}

console.log(err || "Everything went correctly");
Community
  • 1
  • 1
Ionică Bizău
  • 109,027
  • 88
  • 289
  • 474
  • 1
    Global error handlers really don't work in node.js for anything other than shutting down your server because they can't know exactly the context of what went wrong and how to recover. The better scheme these days is to use promises for all async code and then catch errors at least at the top level of your promises where you can actually handle the error. Promises will catch exceptions for you automatically and turn them into promise error handlers. – jfriend00 Nov 29 '15 at 19:20
  • @jfriend00 In my case, I cannot control that since this is a function provided by the user and I really don't want to break the process when error happens. Maybe the `vm` module could be a solution? – Ionică Bizău Nov 29 '15 at 19:27
  • 1
    User-supplied code can do horrible things to your server and you cannot protect yourself from it unless you run it in a separate and sandboxed process. The `vm` module would probably prove useful, but even then you will have to be careful. – jfriend00 Nov 29 '15 at 19:29
  • @jfriend00 In my case, the developer provides the code as functions and my library I am writing should handle any errors in the functions. – Ionică Bizău Nov 29 '15 at 19:38
  • You can't catch errors in async operations in developer supplied code. They just don't bubble up to the top layer. You can put try/catch around anything you call of theirs and that's about all you can do. Beyond that it's up to the developer supplied code to be smart about handling their own errors. – jfriend00 Nov 29 '15 at 19:39

2 Answers2

3

Since you're real problem here is apparently how to protect your server from user-supplied code, you will need to get the user supplied code out of your main process and in a sandboxed environment that cannot do bad things to your server or server's file system. I'd suggest you start with the vm module, but even then there is plenty to read about how to protect your system.

You may also be interested in the vm2 module which adds some additional safety features on top of the vm module.

Some related articles:

Safely sandbox and execute user submitted JavaScript?

How to run user-submitted scripts securely in a node.js sandbox?

A Nifty Javascript Sandbox for Node.js

Node.js Virtual Machine (vm) Usage

Using Docker to Sandbox Untrusted Node JS Code


If you're just trying to catch errors in any code that has been supplied to you by a developer, pretty much all you can do is to put try/catch around anything you call from the outside world.

If the 3rd party code has errors in async code, those will not bubble up to any top level so there's nothing you can do about those. You also can't prevent this 3rd party code from leaking resources (like file handles, memory, etc...).

Basically, if you're going to run the 3rd party code in your process, you need to trust that it's good code, is well written, doesn't leak, handles its own errors and doesn't try to do malicious things. If you can't trust all those things, then it should be run out of process in a sandbox where you at least have a few more protections.

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • It's not really a server case here, but it's good to know that. In my case, I'm writing a unit-testing library for Node.js. Can you add an example, please? – Ionică Bizău Nov 29 '15 at 19:37
  • @IonicăBizău - There are plenty of articles written with examples and tutorials. See the links I've added to my answer. And, if you want better help, you would edit your question to define in much more detail the problem you're actually trying to solve. Right now, your question asks about one solution you tried and does not actually describe the overall problem you're trying to solve. – jfriend00 Nov 29 '15 at 19:38
  • Sure, I improved my question. I'm checking the links. I already googled a lot but ended by asking this question. :D – Ionică Bizău Nov 29 '15 at 19:42
  • @IonicăBizău - I added more to the end of my answer. – jfriend00 Nov 29 '15 at 19:44
  • *If the 3rd party code has errors in async code, those will not bubble up to any top level so there's nothing you can do about those.* –– the `domain` module **can** do that and I want to find the good way to do that today, because I want to show friendly errors to the user. – Ionică Bizău Nov 29 '15 at 19:45
  • @IonicăBizău - I don't think what you're asking for exists and the reason it doesn't exist is because you can't safely recover from a deep error by handling it at the top level. Here's a quote from the domain module documentation: ***This module is pending deprecation. Once a replacement API has been finalized, this module will be fully deprecated. Most end users should not have cause to use this module. 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.*** – jfriend00 Nov 29 '15 at 19:48
  • It does exist currently via the `domain` module, but since that's going to be deprecated, how can I solve that? By looking at the code, the `domain` stuff ends in some [C++ code](https://github.com/nodejs/node/blob/a881b5395461227f040dc51db21947810e707bc0/src/node.cc#L982-L1018). – Ionică Bizău Nov 29 '15 at 20:00
  • @IonicăBizău - Did you ***read*** what's I quote from the domain module doc? There is NO replacement yet. It tells you right there that if you need this functionality, then your only option is to use the domain module for now and just know that you will have to migrate to something else in the future. This type of functionality cannot be built with Javascript only. It has to be built into the JS engine so you cannot build it yourself without hacking the V8 JS engine in C++. – jfriend00 Nov 29 '15 at 20:02
  • I did read it since I already quoted it in my question. ;-) Got it! So, the answer is *there is no alternative yet*. :-) – Ionică Bizău Nov 29 '15 at 20:05
  • @IonicăBizău - Yes, that is the answer. No alternative yet. Use it for now if you need it. Be ready to change to something else in the future. – jfriend00 Nov 29 '15 at 20:06
  • Thanks for clarifying––got it! :-) Peace! – Ionică Bizău Nov 29 '15 at 20:06
1

From all I understand there is no drop-in replacement for domain. Also there are two major efforts to replace it's functionalities:

  • AsyncWrap, which keeps track of context, but isn't exposed directly to userland
  • increase debuggability, through v8 and Chrome Dev Tools, see here

Apart from that using vm sounds suiting for your case.

eljefedelrodeodeljefe
  • 6,304
  • 7
  • 29
  • 61
  • *Apart from that using vm sounds suiting for your case.* –– Is there a way to catch errors when running code in context (e.g. something like `runCode("foo").on("error")`)? Thanks! – Ionică Bizău Nov 30 '15 at 06:24