2

I have a list of promises invoking other AWS Lambdas from inside an AWS Lambda:

promiseArray.push(lambda.invoke(params).promise())

In another function, I iterate over these promises and try resolve them:

for (let i = 0; i < promiseArray.length; i++) {
    try {
        let result = await promiseArray[i];
        console.log("Success!");
    } catch (e) {
        console.log("Failed!");
    }
}

Here's the issue I'm facing. Often times, the invoke throws a TimeoutError that doesn't get captured by the try-catch block and terminates Lambda execution by throwing an "Unhandled Promise Rejection" error. Note that this started appearing only after we upgraded from Node 8.10 to 12.x on the Lambda.

spoderman
  • 51
  • 1
  • 7

1 Answers1

5

The issue lies in the fact the promises are executed immediately after they are created, not when they are awaited upon.

From the Promise documentation:

The executor function is executed immediately by the Promise implementation, passing resolve and reject functions (the executor is called before the Promise constructor even returns the created object)

Considering you are using a custom 1 second timeout, I would say some of these promises are failing even before you reach your loop to wait for them, where you have a try-catch block.

To only run the promises in this try-catch block, you can refactor your code a bit to not create the promise before, but only in the loop. Something along the lines of this:

for (let i = 0; i < params.length; i++) {
    try {
        let result = await lambda.invoke(params[i]).promise();
        console.log("Success!");
    } catch (e) {
        console.log("Failed!");
    }
}
Alberto Trindade Tavares
  • 10,056
  • 5
  • 38
  • 46
  • Thank you. This seems to be the case, explains the intermittent nature of the error. But the above snippet is only as effective as writing synchronous invocation. I'll need to figure how to invoke async while avoiding the original error. – spoderman Mar 09 '20 at 12:32
  • 1
    Yes, you are correct. You could use `Promise.all` to parallelize the invocations, but as you mentioned in a comment, if a single promise fails, you want the others to continue. You can take a look at some answers from here to implement Promise.all without this fail fast behaviour: https://stackoverflow.com/questions/31424561/wait-until-all-promises-complete-even-if-some-rejected – Alberto Trindade Tavares Mar 09 '20 at 12:35