-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
y u no use domain? #19
Comments
Hello.
The actual output is:
I expect that the output would be the following:
|
If you could write a trycatch function body that it supported exception bubbling it would be great. |
@carlos8f I'd prefer to use domains, but for now they're insufficient to truly implement an aysnchronous try/catch. |
@AlexeyKupershtokh how about this? var domain = require('domain');
require('longjohn');
function trycatch (fn, cb) {
var d = domain.create();
d.on('error', function (err) {
try {
cb(err);
}
catch (e) {
if (domain.active) domain.active.exit();
if (domain.active && !domain.active._disposed) {
domain.active.emit('error', e);
}
else {
throw e;
}
}
});
d.run(fn);
}
trycatch(function outerFn () {
console.error('outer fn 1');
trycatch(function innerFn () {
console.error('inner fn 1');
throw new Error('test');
console.error('inner fn 2');
}, function innerCb (err) {
console.error('inner cb');
throw err;
});
console.error('outer fn 2');
}, function outerCb () {
console.error('outer cb');
});
console.error('after'); outputs
@CrabDude I'm curious what you mean by "truly" :) Would be something good to put in the README at least. |
|
|
Curiously. Why is that? Also I doubt that you'll always have |
Not possible since it's "by design" that if you throw inside a domain error listener, the process will crash. My workaround just dodges that crash by manually sending the error to the next outer domain. I admit that I don't know all the ramifications going on here. Just playing devil's advocate on the project's use case. I can't find a way yet to prevent the code flow from aborting (in my example above) so that's one compelling thing about trycatch. |
Carlos, this is all very promising. Here's what I have so far: var domain = require('domain');
function trycatch (fn, cb) {
var d = domain.create();
function onError(err) {
if (domain.active) domain.active.exit();
if (domain.active && !domain.active._disposed) {
try {
domain.active.run(function() {
cb(err);
});
} catch(e){
domain.active.emit('error', e)
}
} else {
cb(err);
}
}
d.on('error', onError);
try {
d.run(fn)
} catch(eIgnore) {}
}
module.exports = trycatch It resolves the logs in the correct order:
Also, there are several other reasons trycatch hasn't been switched over to domains yet either:
Because of this, I haven't looked into yet any effects domains would have on long-stack-traces. |
Actually, this is failing on nested domains which is the primary issue with why domains don't work, but it seemed your solution may have solved it. Unfortunately, it doesn't look to be that way now that I'm playing with it. =( Here's a failing test-case that prevents use of domains: var domain = require('domain')
var assert = require('assert')
var count = 0
var d1 = domain.create()
d1.run(function () {
process.nextTick(function() {
var d2 = domain.create()
d2.run(function () {
process.nextTick(function() {
// THE PROBLEM IS HERE
// IT SEEMS domain._stack POPPED THE WRONG DOMAIN
// WHICH RESULTS IN THE OUTER CATCH NEVER BEING CALLED
assert.equal(domain._stack[0], d1)
++count
throw new Error('test 2')
}, 0)
})
d2.on('error', function(err) {
console.log('inner')
;++count
throw err;
})
}, 0)
})
d1.on('error', function(err) {
console.log('outer')
++count
assert.equal(err.message, 'test 2')
assert.equal(count, 3)
console.log('success!')
}) |
Posted Issue: #4733 |
Alright, here's an update. It looks like if we merely keep track of the parent domain, and manually run the catchFn in the parent domain, Here's the domain solution I currently have that's passing all unit tests: var domain = require('domain');
function trycatch (fn, cb) {
var activeDomain = domain.active
, d = domain.create()
d.on('error', function onError(err) {
if (!(err instanceof Error)) {
err = new Error(err)
}
run(activeDomain, function() {
cb(err)
})
})
run(d, fn)
}
function run(d, fn) {
if (d && !d._disposed) {
try {
d.run(fn)
} catch(e) {
d.emit('error', e)
}
} else {
fn()
}
}
module.exports = trycatch Carlos, thanks for helping with the first draft. Now I need to see if there's a way to add long-stack-traces to the domain solution, or if that still requires hooking into everything. |
hey, looks pretty good! although, I haven't looked at the node 0.9 domain implementation yet, I wonder if the approach would be broken. longjohn already provides long stack traces, right? |
longjohn's using the same hack as trycatch (and tlrobinson/long-stack-traces#9 (comment) While it looks like there's a possibility longjohn has addressed some of this, I'm 100% confident the trycatch/lib/hook implementation has addressed it. I'll look into this a little more, and work out a solution. |
First version of domain-based trycatch is up on master. Check it out and let me know what you think. It's actually kind of a Franken-solution. Long-stack-traces are off by default, which means no low-level shimming / hooking is required, which is really nice. If you decide to turn them on, you should call |
The text was updated successfully, but these errors were encountered: