Forum Academy Marketplace Showcase Pricing Features

Error not caught in SSA (empty) with async - how to catch it?

Hey guys,

In the following structure, if, let’s say Package.getDogfails, the error is properly shown in the front-end debugger, however I can’t manage to get any message in the console in the outer catch (err), in which err is desperately empty.

function(properties, context) {
    const Package = required('package')
    const parameters = {
        param1
    };
    return context.async(async callback => {
        try {
            function processingAnimals(params) {
                return new Promise((resolve, reject) => {
                    try {
                        Package.getDog(params)
                            .then(function(responseFromGetDog) {
                                return resolve(responseFromGetDog);
                            })
                            .catch((error) => {
                                reject(error);
                            });
                    } catch (error) {
                        reject(error);
                    };
                });
            };
            var response = await processingAnimals(parameters);
            callback(undefined, response);
        } catch (err) {
            console.log("Error "+err);         <-------- Error {}
            callback(err);
        }
    });
}

Any suggestion on how to properly get the error message in the outer catch ?

Thanks

I had to dig around to find the reference. Console logging for server actions are written to the server log.

Thanks @aaronsheldon for your response.

What I am trying to achieve is to catch the error from the code itself. I suspect that the err is passed to the engine level, and is somehow bypassing the catch- which seems however unlikely ?

Error handling patterns with Promises are tricky. This isn’t the article I original read “Error Propagation in JavaScript with Error Translation Pattern”, however it does cover how to pattern error handling. There is also the Mozilla documentation.

I believe the source of your problems is in how you are calling processingAnimals. The outer catch is swallowing the inner error. Refactoring the try catch block yields:

return context.async(async callback => {
    function returnAPromise(...) { return new Promise... };
    var response = await returnAPromise(...).catch(err => {console.log(err); callback(err);});
    callback(undefined, response);
});

Addendum

I have adopted a pattern of micro-dispatching then to Fibre co-routines using context.async, and moving all the logic and control flow into the synchronous execution. The pattern looks like:

// Do synchronous stuff
...

// Micro-dispatch await to Fibre co-routine
var thened = context.async(
    callback => somePromise
    .then(thening => callback(null, thening))
    .catch(reason => callback(reason))
);

// Do synchronous stuff with the returned result
...

Admittedly this involves a fair bit of scope mangling within the stack of the server function. Once my current project slows down I’m planning to bench mark the following three Server Side Action patterns:

  1. Monolithic iteration inside of a context.async.
  2. Monolithic iteration over micro-dispatched context.async.
  3. Workflow recursive iteration over “Little Lambda” actions that contain micro-dispatched context.async.

From my experience with other languages like Julia, I suspect the last pattern will have the best scaling performance as it can reuse the JIT compile on the “Little Lambda” actions; even if it is initially slower for small iterations. As well moving iteration out of the action code and into the workflow gives the server a better shot at load balancing and throttling and I think would lessen the chance of an action being cancelled outright because of timeouts.

1 Like

Thanks for your addendum @aaronsheldon.

Would you mind to elaborate which scenarios would solve the uncaught errors issues, or what would be the difference in error handling ?

So far the micro-dispatching with promise.then().catch() seems to be passing errors to the log in server side actions. I’m trying to get NodeMailer’s SimpleParser running and it is bombing on some incorrectly formatted raw emails. So I have been getting javascript “Error undefined reference: x at eval” errors where the parse is failing on the bad input.

1 Like

Found it! There is also this little gem, deprecating async {await} and try {} catch {} in favour of .then().catch():

Note: When writing server-side actions, avoid using async/await syntax to wait for promises. The framework we use to to handle asynchronous code (notably used in context.async or context.request) relies on a special library called “Fibers”, which works very differently from usual promises and will cause unexpected behavior if async/await is used. Consider using the traditional Promise.then/catch syntax instead, which is supported by Fibers.

2 Likes

Haha! Great!
How does your implementation scenarios factor in with regards to this new finding ?

I’ve used async await with 0 issue in server side actions so far.

I sure hope I remember this ^^^^ when that syntax begins to fail!

1 Like

Not quite new. I remembered that I decided on the pattern after reading a snippet somewhere. I just had to dig it up again. Particularly in light that the Node Fibres module has a very stern deprecation obsolescence warning at the top of it. Which means “do’n any new highfalutin things” might break the code. Long story short Node Fibres was written before syntax for generators, co-routines, and async/await was added to the Javascript standard. But I’ll let the Bubble engineers sweat over that.