Aviram Fireberger
Aviram Fireberger

Reputation: 4178

AWS Lambda finish before sending message to SQS

I'm running a "Node.JS" lambda on AWS that sends a message to SQS. For some reason the SQS callback function get execute only once every couple of calls. It's looks like that the thread that running the lambda finish the run (because it's not a synchronous call to SQS and also can't return a Future) and therefore the lambda doesn't "stay alive" for the callback to get executed.

How can I solve this issue and have the lambda wait for the SQS callback to get execute?

Here is my lambda code:

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

// Set the region
AWS.config.update({region: 'us-east-1'});

// Create an SQS service object
var sqs = new AWS.SQS({apiVersion: '2012-11-05'});
const SQS_QUEUE_URL = process.env.SQS_QUEUE_URL;

var params = {
    MessageGroupId: "cv",
    MessageDeduplicationId: key,
    MessageBody: "My Message",
    QueueUrl: SQS_QUEUE_URL
};

console.log(`Sending notification via SQS: ${SQS_QUEUE_URL}.`);
sqs.sendMessage(params, function(err, data) {   //<-- This function get called about one time every 4 lambda calls
    if (err) {
        console.log("Error", err);
        context.done('error', "ERROR Put SQS");  
    } else {
        console.log("Success", data.MessageId);
        context.done(null,'');  
    }
});

};

Upvotes: 8

Views: 4740

Answers (1)

Vladyslav Usenko
Vladyslav Usenko

Reputation: 2376

You should either stick to callback based approach, or to promise based one. I recommend you to use the latter:

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

  // Set the region
  AWS.config.update({region: 'us-east-1'});

  // Create an SQS service object
  var sqs = new AWS.SQS({apiVersion: '2012-11-05'});
  const SQS_QUEUE_URL = process.env.SQS_QUEUE_URL;

  var params = {
      MessageGroupId: "cv",
      MessageDeduplicationId: key,
      MessageBody: "My Message",
      QueueUrl: SQS_QUEUE_URL
  };

  console.log(`Sending notification via SQS: ${SQS_QUEUE_URL}.`);
  try {
      await sqs.sendMessage(params).promise(); // since your handler returns a promise, lambda will only resolve after sqs responded with either failure or success
  } catch (err) {
    // do something here
  }
};

P.S. Instantiating aws classes in the handler is not a good idea in lambda environment, since it increases the cold start time. It's better to move new AWS.SQS(...) action out of handler and AWS.config.update() too, since these actions will be executed on each call of the handler, but you really need them to be executed only once.

Upvotes: 13

Related Questions