Posted: 13 Dec 2012
Categories:
node.js
software engineering
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.
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
1 var domain = require('domain');
2 var redis = require('redis');
3 var eventEmitter = require('events').EventEmitter;
4
5 var tests = [];
6 var testCounter = 0;
7 var runTest = function(){
8 if(tests.length > testCounter){
9 tests[testCounter]();
10 }else{
11 console.log("all done!")
12 process.exit();
13 }
14 }
15
16 var myDomain = new domain.create();
17 myDomain.on('error', function(err){
18 console.log('Yo, I just saved you from the error: ' + err);
19 testCounter++;
20 runTest();
21 });
22
23 // PASSING
24 tests[0] = function(){
25 myDomain.run(function(){
26 throw new Error('A simple error');
27 });
28 };
29
30 // PASSING
31 tests[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
48 var Emm = new eventEmitter;
49 Emm.on('thing', function(){
50 throw new Error('Emmited Error defined outside of scope');
51 })
52 tests[2] = function(){
53 myDomain.run(function(){
54 setTimeout(function(){
55 Emm.emit('thing');
56 }, 100)
57 })
58 };
59
60 // PASSING
61 tests[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
71 tests[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
81 clientC = redis.createClient();
82 tests[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
91 runTest();
throw in the scope of running domian. Everything works great.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.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. Cross-Posted on GitHub
<< What do you do when softpedia scrapes you projects? Delete old git branches already merged into master >>
Follow me on Twitter Follow me on Github