Search code examples
javascriptamazon-web-servicesaws-lambdaes6-promiseamazon-sqs

Why does my Lambda function send an SQS message twice with one call?


I need to only deliver a message to a standard (not FIFO, but is not related to the question) SQS queue, once with one call.

However, the code below is sending 2 messages with 1 call.

const AWS = require('aws-sdk')
AWS.config.update({region: process.env.AWS_REGION})
const sqs = new AWS.SQS({apiVersion: '2012-11-05'});

async function sendToSQSEvent(body,attributes=null){
    var m_body 
    if (attributes != null)
    {
            m_body = {
                body : body,
                attributes : attributes
                };
    }
    else{
        m_body = body;
    }
    m_body = JSON.stringify(m_body);
            
 var params = {
    //  DelaySeconds: 0,   <-- i try but only delay reception 
      MessageAttributes: {
        "Title": {
          DataType: "String",
          StringValue: "TIME_OUT"
        },
        "Author": {
          DataType: "String",
          StringValue: "LAMBDA_IN"
        },
      },
      MessageBody: m_body,
      QueueUrl: "https://my_url/sqs"
    };
    console.log('_________CALL_______________');
    var r = await sqs.sendMessage(params, function(err, data) {
      if (err) {
        console.log("Error", err);
      } else {
        console.log("Success", data.MessageId ,data);
      }
    }).promise(console.log("_________in promise___________"));
   console.log("___end")
}

exports.handler = async (event, context) => {
     await sendToSQSEvent(event)
};

Console output is:

START RequestId: RequestId Version: $LATEST
2021-10-11T06:23:52.992Z    RequestId   INFO    _________CALL_______________
2021-10-11T06:23:53.425Z    RequestId   INFO    _________in promise___________
2021-10-11T06:23:53.728Z    RequestId   INFO    Success ********-****-****-****-*********b4f {
  ResponseMetadata: { RequestId: '********-****-****-****-*********89d' },
  MD5OfMessageBody: '********************************8f',
  MD5OfMessageAttributes: '***********************1b0',
  MessageId: '********-****-****-****-*********b4f'
}
2021-10-11T06:23:53.786Z    RequestId   INFO    ___end
2021-10-11T06:23:53.807Z    RequestId   INFO    Success ********-****-****-****-*********665 {
  ResponseMetadata: { RequestId: '********-****-****-****-********835' },
  MD5OfMessageBody: '***********************28f',
  MD5OfMessageAttributes: '***********************1b0',
  MessageId: '********-****-****-****-*********665'
}
END RequestId: RequestId

What is the issue?


Solution

  • It's sending a message twice as you're mixing synchronous callbacks (function(err, data)) with asynchronous promises (await, async function sendToSQSEvent(...)).

    You can see this as CloudWatch is logging 2 sqs.sendMessage(...) responses.

    I would recommend sticking with the latter.


    This should be your SQS sendMessage logic, which returns a promise object for your handler.

    return sqs.sendMessage(params).promise();
    

    You can then check the response in your handler:

    exports.handler = async (event, context) => {
        try {
            var data = await sendToSQSEvent(event)
            console.log("Success", data.MessageId ,data);
        }
        catch (err){
            console.log("Error", err);
        }
    };
    

    This should be the final working result:

    const AWS = require('aws-sdk')
    AWS.config.update({
        region: process.env.AWS_REGION
    })
    const sqs = new AWS.SQS({
        apiVersion: '2012-11-05'
    });
    
    async function sendToSQSEvent(body, attributes = null) {
        var m_body
        if (attributes != null) {
            m_body = {
                body: body,
                attributes: attributes
            };
        } else {
            m_body = body;
        }
        m_body = JSON.stringify(m_body);
    
        var params = {
            MessageAttributes: {
                "Title": {
                    DataType: "String",
                    StringValue: "TIME_OUT"
                },
                "Author": {
                    DataType: "String",
                    StringValue: "LAMBDA_IN"
                },
            },
            MessageBody: m_body,
            QueueUrl: "https://my_url/sqs"
        };
    
        return sqs.sendMessage(params).promise();
    }
    
    exports.handler = async (event, context) => {
        try {
            var data = await sendToSQSEvent(event)
            console.log("Success", data.MessageId ,data);
        }
        catch (err){
            console.log("Error", err);
        }
    };