
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
var domain = require("domain");
var redis = require("redis");
var eventEmitter = require("events").EventEmitter;
var tests = [];
var testCounter = 0;
var runTest = function () {
if (tests.length > testCounter) {
tests[testCounter]();
} else {
console.log("all done!");
process.exit();
}
};
var myDomain = new domain.create();
myDomain.on("error", function (err) {
console.log("Yo, I just saved you from the error: " + err);
testCounter++;
runTest();
});
// PASSING
tests[0] = function () {
myDomain.run(function () {
throw new Error("A simple error");
});
};
// PASSING
tests[1] = function () {
myDomain.run(function () {
setTimeout(function () {
process.nextTick(function () {
var E = new eventEmitter();
E.on("thing", function () {
throw new Error("A deeply nested error");
});
setTimeout(function () {
E.emit("thing");
}, 100);
});
}, 100);
});
};
// PASSING
var Emm = new eventEmitter();
Emm.on("thing", function () {
throw new Error("Emmited Error defined outside of scope");
});
tests[2] = function () {
myDomain.run(function () {
setTimeout(function () {
Emm.emit("thing");
}, 100);
});
};
// PASSING
tests[3] = function () {
myDomain.run(function () {
clientA = redis.createClient();
clientA.hget("hash", "key", function (err, data) {
throw new Error("An error after redis (A)");
});
});
};
// PASSING
tests[4] = function () {
clientB = redis.createClient();
myDomain.run(function () {
clientB.hget("hash", "key", function (err, data) {
throw new Error("An error after redis (B)");
});
});
};
// FAILING
clientC = redis.createClient();
tests[5] = function () {
myDomain.run(function () {
clientC.hget("hash", "key", function (err, data) {
throw new Error("An error after redis (C)");
});
});
};
// start it up
runTest();- 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.