Skip to content

Instantly share code, notes, and snippets.

@dtudury
Last active December 19, 2015 05:29
Show Gist options
  • Save dtudury/5904555 to your computer and use it in GitHub Desktop.
Save dtudury/5904555 to your computer and use it in GitHub Desktop.
behaves differently for sync and async
/*
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();
}
}
@othiym23
Copy link

othiym23 commented Jul 2, 2013

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment