JS code with promise not working on AWS lambda but works when changed to async/await style

I am trying to create a function on AWS Lambda to send SMS to a mobile phone using Twilio API. I am using Node.JS and mostly followed the instructions in this post here: https://www.twilio.com/blog/aws-lambda-layers-node-js-twilio-sms

The code for sending the SMS which I got from that post is this:

exports.handler = (event, context, callback) => {

    // Your Account SID from www.twilio.com/console
    // See http://twil.io/secure for important security information
    const accountSid = process.env.ACCOUNT_SID;

    // Your Auth Token from www.twilio.com/console 
    // See http://twil.io/secure for important security information
    const authToken = process.env.AUTH_TOKEN;

    // Import Twilio's Node Helper library
    // Create an authenticated Twilio Client instance
    const client = require('twilio')(accountSid, authToken);

    // Send a text message
    client.messages.create({
        body: 'Hello from Lambda!',
        to: '+12345678901',  // your phone number
        from: '+12345678901' // a valid Twilio number
    })
        .then((message) => {
            // Success, return message SID
            callback(null, message.sid);
        })
        .catch((e) => {
                // Error, return error object
            callback(Error(e));
        });

};

When I was creating the lambda on AWS I chose a Hello-World template and it had marked the exports.handler callback as async, like this exports.handler = async (event, context, callback) => {. I failed to notice this async keyword and copy pasted the method body from that post, ultimately mixing async/await code with promise style .then code. I first tested this code locally from my computer and it worked because I just used the method body without any top level function or anything. But when I ran this from AWS Lambda, the environment variables were getting logged correctly, but after that I wasnt getting any other O/P or error. After wasting a lot of time, I decided to change the chained promise style code to async/await style code and it worked. My modified code is this:

exports.handler = async (event, context, callback) => {
    // Your Account SID from www.twilio.com/console
    // See http://twil.io/secure for important security information
    const accountSid = process.env.ACCOUNT_SID;

    // Your Auth Token from www.twilio.com/console 
    // See http://twil.io/secure for important security information
    const authToken = process.env.AUTH_TOKEN;

    // Import Twilio's Node Helper library
    // Create an authenticated Twilio Client instance
    const client = require('twilio')(accountSid, authToken);


    try {
        const messageSid = await client.messages.create({
                body: 'Hello from Lambda!',
                to: '+12345678901',  // your phone number
            from: '+12345678901' // a valid Twilio number
        });
    }
    catch(err) {
        callback(Error(err));
    }
};

My question is, is it wrong to mix async/await with promise type code (.then construct)? If I add async keyword in the 1st line of 1st code it doesnt work. Why does this happen?

Upvotes: 1

Views: 1382

Answers (1)

Jason Wadsworth
Jason Wadsworth

Reputation: 8887

You should not combine the two. Details can be found here: AWS Lambda function handler in Node.js.

One key is this:

For non-async handlers, function execution continues until the event loop is empty or the function times out. The response isn't sent to the invoker until all event loop tasks are finished. If the function times out, an error is returned instead. You can configure the runtime to send the response immediately by setting context.callbackWaitsForEmptyEventLoop to false.

When you are NOT using async it will wait for the event loop to finish. It does not do this when you are using async, as it expects you to use async all the way through.

Upvotes: 1

Related Questions