Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS - Lambda Function not waiting for await

I'm using AWSs API Gateway along with a Lambda function for an API.

In my Lambda function, I have the following (simplified) code however I'm finding that the await sendEmail isn't being respected, instead, it keeps returning undefined

exports.handler = async (event) => {
    let resultOfE = await sendEmail("[email protected]", "[email protected]")
    console.log(resultOfE)
}

async function sendEmail(oldEmail, newEmail) {
    var nodemailer = require('nodemailer');

    var transporter = nodemailer.createTransport({
        service: 'gmail',
        auth: {
            user: 'xxx',
            pass: 'xxx'
        }
    });

    transporter.sendMail(mailOptions, function (error, info) {
        if (error) {
            console.log(error);
            return false
        } else {
            console.log('Email sent: ' + info.response);
            return true
        }
    });
}
like image 486
userMod2 Avatar asked Aug 05 '19 00:08

userMod2


People also ask

What is Lambda in AWS Lambda?

Lambda is a compute service in AWS. By lambda we can run serverless applications. For further details go to this link. Using async/await we can write asynchronous function and simplify promise chain. Await keyword is valid only in an async function. ECMAScript 2017 brought this feature which is syntactic sugar on top of promises.

Does AWS Lambda support async and await?

However, the large caveat is that async (along with many other wonderful ES2016 and ES2017 features) isn’t supported on AWS Lambda, according to node.green: No async/await? : ( (

What happens if Lambda is not fully sent over the network?

If we send a HTTP request and that request is not fully sent over the network, if we return from the Lambda function, AWS will immediately suspend our Lambda container AND the partially sent request will be suspended as well.

How to avoid waiting and blocking in lambda functions?

There are many other excellent ways to avoid waiting and blocking in Lambda functions such as using Step functions, SQS queues and directly invoking Lambda functions as Events without waiting.


1 Answers

since you await sendMail, this requires sendMail to return a Promise - your code uses callbacks to handle the asynchrony, so

  • the async sendMail doesn't do anything (except make sendMail return a Promise that IMMEDIATELY resolves to undefined
  • you need to change sendMail to return a Promise (and it won't need async since it won't need await

the code below should do it -

var nodemailer = require('nodemailer'); // don't put require inside a function!!

exports.handler = async (event) => {
    const resultOfE = await sendEmail("[email protected]", "[email protected]")
    console.log(resultOfE)
}

//doesn't need async, since there will be no await
function sendEmail(oldEmail, newEmail) {
    return new Promise((resolve, reject) => { // note, reject is redundant since "error" is indicated by a false result, but included for completeness
        const transporter = nodemailer.createTransport({
            service: 'gmail',
            auth: {
                user: 'xxx',
                pass: 'xxx'
            }
        });
        transporter.sendMail(mailOptions, (error, info) => {
            if (error) {
                console.log(error);
                resolve(false);
            } else {
                console.log('Email sent: ' + info.response);
                resolve(true);
            }
        });
        // without the debugging console.logs, the above can be just
        // transporter.sendMail(mailOptions, error => resolve(!error));
    });
}

as per comment by @ThalesMinussi, transporter.sendMail returns a Promise if you do not provide a callback function, so you could write: (sendEmail is now async)

async function sendEmail(oldEmail, newEmail) {
    const transporter = nodemailer.createTransport({
        service: 'gmail',
        auth: {
            user: 'xxx',
            pass: 'xxx'
        }
    });
    try {
        const info = await transporter.sendMail(mailOptions);
        console.log('Email sent: ' + info.response);
        return true;
        }
    } catch (error) {
        console.log(error);
        return false;
    }
}
like image 175
Jaromanda X Avatar answered Oct 16 '22 23:10

Jaromanda X