Last active
December 19, 2015 05:29
-
-
Save dtudury/5904555 to your computer and use it in GitHub Desktop.
behaves differently for sync and async
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
if I call "node experiment async": | |
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv | |
I can haz world? | |
..c0 begin | |
..c0 end | |
....c1 begin | |
....c1 end | |
......c2 begin | |
......c2 end | |
........thrower begin | |
.......c2 error begin | |
.......c2 error: Error: I'm the error | |
process-wide exit handler | |
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
and if I call "node experiment sync": | |
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv | |
I can haz world? | |
..c0 begin | |
....c1 begin | |
......c2 begin | |
........thrower begin | |
.......c2 error begin | |
.......c2 error: Error: I'm the error | |
.....c1 error begin | |
.....c1 error: Error: I'm the error | |
...c0 error begin | |
...c0 error: Error: I'm the error | |
process-wide exit handler | |
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
I feel like when using domains: errors shouldn't get caught multiple times ever | |
*/ | |
var domain = require('domain'); | |
console.log("I can haz world?"); | |
process.on('exit', function() { | |
console.log("process-wide exit handler"); | |
}); | |
process.on('uncaughtException', function(error) { | |
console.log(".uncaughtException begin"); | |
console.log(".uncaughtException: " + error); | |
process.exit(1); | |
console.log(".uncaughtException end"); | |
}); | |
c0(); | |
function c0() { | |
var callback = function() { | |
console.log("..c0 begin"); | |
var d = domain.create(); | |
d.on('error', function(error) { | |
console.log("...c0 error begin"); | |
console.log("...c0 error: " + error); | |
throw error; | |
console.log("...c0 error end"); | |
}); | |
d.run(c1); | |
console.log("..c0 end"); | |
}; | |
if(process.argv.indexOf('sync') === -1) { | |
process.nextTick(callback); | |
} else { | |
callback(); | |
} | |
} | |
function c1() { | |
var callback = function() { | |
console.log("....c1 begin"); | |
var d = domain.create(); | |
d.on('error', function(error) { | |
console.log(".....c1 error begin"); | |
console.log(".....c1 error: " + error); | |
throw error; | |
console.log(".....c1 error end"); | |
}); | |
d.run(c2); | |
console.log("....c1 end"); | |
}; | |
if(process.argv.indexOf('sync') === -1) { | |
process.nextTick(callback); | |
} else { | |
callback(); | |
} | |
} | |
function c2() { | |
var callback = function() { | |
console.log("......c2 begin"); | |
var d = domain.create(); | |
d.on('error', function(error) { | |
console.log(".......c2 error begin"); | |
console.log(".......c2 error: " + error); | |
throw error; | |
console.log(".......c2 error end"); | |
}); | |
d.run(thrower); | |
console.log("......c2 end"); | |
}; | |
if(process.argv.indexOf('sync') === -1) { | |
process.nextTick(callback); | |
} else { | |
callback(); | |
} | |
} | |
function thrower() { | |
var callback = function() { | |
console.log("........thrower begin"); | |
throw new Error("I'm the error"); | |
console.log("........thrower end"); | |
}; | |
if(process.argv.indexOf('sync') === -1) { | |
process.nextTick(callback); | |
} else { | |
callback(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It seems to me that the behavior that results from throwing within a domain's error handler should be treated as undefined. We stressed this in some sessions but not others, but it's very important that the error handlers be as close to pure and safe as you can make them; if the handler throws, you'll get the error that was passed to the handler, not the error generated by the handler. This caused a lot of confusion at NodeConf, because it looks like the domain isn't doing anything at all.
The reason the sync and async versions work differently is that EventEmitter methods run synchronously, so in the sync case, all three callbacks are on one call stack and so the throw bubbles back up through them. This is an interesting anomaly, but it isn't a bug on its own. If you can come up with a case where a single (thrown) error gets emitted on multiple domains without a domain handler explicitly rethrowing it, that would probably be a bug.