luciotato / waitfor

Sequential programming for node.js, end of callback hell / pyramid of doom
MIT License
531 stars 29 forks source link

problem with exceptions thrown in launchFiber after wait.for #12

Closed yelworc closed 10 years ago

yelworc commented 10 years ago

When a wait.launchFiber call is surrounded by a try-catch block, only exceptions thrown before the first wait.for inside the fiber are caught, e.g.:

var fs = require('fs');
var wait = require('wait.for');

function test(testcase) {
    if (testcase === 1) {
        throw new Error('test case 1, exception thrown before wait.for');
    }
    wait.for(fs.stat, 'waitfor-exception-problem.js');
    if (testcase === 2) {
        throw new Error('test case 2, exception thrown after wait.for');
    }
}

try {
    wait.launchFiber(test, 1);
}
catch (e) {
    // exception is safely caught here
    console.log('caught: %s', e);
}
try {
    wait.launchFiber(test, 2);
}
catch (e) {
    // exception is *not* caught here!
    console.log('caught: %s', e);
}

Output:

$ node waitfor-exception-problem.js
caught: Error: test case 1, exception thrown before wait.for

[...]\node_modules\wait.for\waitfor.js:40
                                else throw e;
                                           ^
Error: test case 2, exception thrown after wait.for
    at test ([...]\waitfor-exception-problem.js:11:9)
    at [...]\node_modules\wait.for\waitfor.js:15:31

This is unexpected at best. According to comments on issues in the node-fibers repo, this is "normal" behavior for fibers, and the higher-level library is supposed to make this more manageable for the user:

Could this be be improved somehow in wait.for?

luciotato commented 10 years ago

launchFiber _returns_ at the first wait-for, that's why it doesnt catch the exception, and also why it's called "launch". You "launch" the fiber and forget about it, the fiber runs in another context. . Once launched, you loose control. It's like launching a pseudo-parallel thread.

This is important: launchFiber normally _returns_ before the fiber runs to completion, that's whats makes node be able to handle other requests.

If you need more help, please paste the real use case, form what you say, It seems you're not understanding the functions correctly.

yelworc commented 10 years ago

Ah -- I did misunderstand how launchFiber works, but as you say, the name is pretty clear, so my bad. Thanks for clearing that up.

My use case is fairly standard: A function that calls several asynchronous functions sequentially without blocking the event loop using wait.for (like your handleWithdrawal example), and I want simple error handling in the caller of that function. If I understand it correctly, I need to do something like this:

var fs = require('fs');
var wait = require('wait.for');

function test(callback) {
    wait.launchFiber(function() {
        try {
            wait.for(fs.stat, 'a-file-that-exists');  // works
            wait.for(fs.readFile, 'does-not-exist');  // throws exception
        }
        catch (e) {
            callback(e);
        }
    });
}

test(function callback(err, res) {
    if (err) {
        console.log('oops: %s', err);
    }
});