On Domains and Connections with node.js

javascript node.js 
Thu Dec 13 2012



Solved!

The reason for this question was to ensure that in actionHero exceptions thrown after a call to the api.cache methods would still be caught by the domain they should have been in. Here is the commit which force-binds callbacks from the redis client back to the domain they should have been in. This is needed due to the fact that connection-pooled clients (which were created before the domain) will always revert back to their original scope.

The Question:

I’ve been having trouble lately with domains in node.js, in that I have found a few occasions where what is ‘in scope’ confuses me. Here’s a collection of tests to illustrate my I set up the test to have a domain which I will run each test in, and I expect all of the tests to throw an error and to be caught by the domain’s on(‘error’) event. I chose to use a redis client here (because it’s common), but I do not think that this is a problem with the awesome redis package, and I’ve observed similar behavior with the mysql / seq All of the tests work except #4, which throws an out-of-domain exception and causes the script to crash

1var domain = require("domain"); 2var redis = require("redis"); 3var eventEmitter = require("events").EventEmitter; 4 5var tests = []; 6var testCounter = 0; 7var runTest = function () { 8 if (tests.length > testCounter) { 9 tests[testCounter](); 10 } else { 11 console.log("all done!"); 12 process.exit(); 13 } 14}; 15 16var myDomain = new domain.create(); 17myDomain.on("error", function (err) { 18 console.log("Yo, I just saved you from the error: " + err); 19 testCounter++; 20 runTest(); 21}); 22 23// PASSING 24tests[0] = function () { 25 myDomain.run(function () { 26 throw new Error("A simple error"); 27 }); 28}; 29 30// PASSING 31tests[1] = function () { 32 myDomain.run(function () { 33 setTimeout(function () { 34 process.nextTick(function () { 35 var E = new eventEmitter(); 36 E.on("thing", function () { 37 throw new Error("A deeply nested error"); 38 }); 39 setTimeout(function () { 40 E.emit("thing"); 41 }, 100); 42 }); 43 }, 100); 44 }); 45}; 46 47// PASSING 48var Emm = new eventEmitter(); 49Emm.on("thing", function () { 50 throw new Error("Emmited Error defined outside of scope"); 51}); 52tests[2] = function () { 53 myDomain.run(function () { 54 setTimeout(function () { 55 Emm.emit("thing"); 56 }, 100); 57 }); 58}; 59 60// PASSING 61tests[3] = function () { 62 myDomain.run(function () { 63 clientA = redis.createClient(); 64 clientA.hget("hash", "key", function (err, data) { 65 throw new Error("An error after redis (A)"); 66 }); 67 }); 68}; 69 70// PASSING 71tests[4] = function () { 72 clientB = redis.createClient(); 73 myDomain.run(function () { 74 clientB.hget("hash", "key", function (err, data) { 75 throw new Error("An error after redis (B)"); 76 }); 77 }); 78}; 79 80// FAILING 81clientC = redis.createClient(); 82tests[5] = function () { 83 myDomain.run(function () { 84 clientC.hget("hash", "key", function (err, data) { 85 throw new Error("An error after redis (C)"); 86 }); 87 }); 88}; 89 90// start it up 91runTest();
  • Test #0 is a simple throw in the scope of running domian. Everything works great.
  • Test #1 is a very convoluted throw in the scope of the domain involving timeouts, process.nextTick, and event emitters (I was trying to break things). Node preforms like a boss, and the eventual throw is caught.
  • Test #2 defines the emitter outside of the domain, but invokes the event from within it. Still the error is caught.
  • Test #3 creates the redis client within the scope of the domain. The error is caught and all is well
  • Test #4 creates the redis client OUTSIDE of the domain’s scope, but within a containing function. This error is caught by the domain
  • Test #5 fails, and the redis client here is created before the tests begin to run.

In all of these cases, I would have hoped for the domain to catch the exceptions. I also would have also expected tests #4 and #5 to behave the same way regardless of whether or n Can anyone help me to explain why test 5 fails? domain can have their exceptions caught by it.

Hi, I'm Evan

I write about Technology, Software, and Startups. I use my Product Management, Software Engineering, and Leadership skills to build teams that create world-class digital products.

Get in touch