0

Trying to send several messages (from AWS SQS lambda, if that matters) but it's never waiting for the promises.

function getEndpoint(settings){
    return new Promise(function(resolve, reject) { 
    // [...] more stuff here
}

Which is then called in a loop:

exports.handler = async (event) => {
    var messages = [];
    event.Records.forEach(function(messageId, body) {
        //options object created from some stuff
        messages.push(getEndpoint(options).then(function(response){
            console.log("anything at all"); //NEVER LOGGED
        }));
    });
    await Promise.all(messages);
};

But the await seems to be flat out skipped. I'm not sure how I'm getting Process exited before completing request with an explicit await. I have similar async await/promise setups in other scripts that work, but cannot spot what I've done wrong with this one.

4
  • Mind sharing more code? This excerpt looks alright. Commented Apr 30, 2019 at 13:59
  • @enapupe added the remote call function in, but that's really just about the whole thing Commented Apr 30, 2019 at 14:01
  • Would like to see the main invoked fn body.. which you shared just part of. The getEndpoint part seems ok Commented Apr 30, 2019 at 14:02
  • @enapupe with the exception of the actual https call settings (which I can't share, for security reasons) everything is here. But if that were the issue, I'd be getting errors, no? Commented Apr 30, 2019 at 14:06

1 Answer 1

5

You forgot to return something to lambda:

exports.handler = async (event) => {
    var messages = [];
    event.Records.forEach(function(messageId, body) {
        //options object created from some stuff
        messages.push(getEndpoint(options));
    });
    await Promise.all(messages);
    return 'OK'
};

this should also work:

exports.handler = (event) => { // async is not mandatory here
    var messages = [];
    event.Records.forEach(function(messageId, body) {
        //options object created from some stuff
        messages.push(getEndpoint(options));
    });
    return Promise.all(messages); // returning a promise
};

and you could use map:

exports.handler = (event) => { // async is not mandatory here
    const messages = event.Records.map(function(messageId, body) {
        //options object created from some stuff
        return getEndpoint(options)
    });
    return Promise.all(messages); // returning a promise
};

To understand why this happens, you must dive a bit into lambda's implementation: it will essentially wait for the function stack to be cleared and since you did NOT return anything at all in there, the function stack got empty right after it queued all the stuff - adding a simple return after the await call makes the fn stack to NOT be empty which means lambda will wait for it to be finished.

If you run this on standard node, your function would also return before the promises were finished BUT your node process would NOT exit until the stack was cleared. This is where lambda diverges from stock node.

Sign up to request clarification or add additional context in comments.

1 Comment

Fantastic. Thanks for all the detail, it's good to have the understanding of what's going on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.