AWS SQS messages does not become available again after visibility timeout

All we need is an easy explanation of the problem, so here it is.

This is most likely something really simple but for some reason my SQS messages does not become available again after visibility timeout. At least this is what I figured since consuming lambda has no log entries indicating that any retries have been triggered.

My use case is that another lambda is feeding SQS queue with JSON entities that then needs to be sent forward. Sometimes there’s so much data to be sent that receiving end is responding with HTTP 429.

My sending lambda (JSON body over HTTPS) is deleting the messages from queue only when service is responding with HTTP 200, otherwise I do nothing with the receiptHandle which I think should then keep the message in the queue.

Anyway, when request is rejected by the service, the message does not become available anymore and so it’s never tried to send again and is forever lost.

Incoming SQS has been setup as follows:

  • Visibility timeout: 3min
  • Delivery delay: 0s
  • Receive message wait time: 1s
  • Message retention period: 1d
  • Maximum message size: 256Kb

Associated DLQ has Maximum receives of 100

AWS SQS messages does not become available again after visibility timeout

The consuming lambda is configured as

  • Memory: 128Mb
  • Timeout: 10s
  • Triggers: The source SQS queue, Batch size: 10, Batch window: None

AWS SQS messages does not become available again after visibility timeout

And the actual logic I have in my lambda is quite simple, really. Event it receives is the Records in the queue. Lambda might get more than one record at a time but all records are handled separately.

console.log('Response', response);

if (response.status === 'CREATED') {

  /* some code here */

  const deleteParams = {
    QueueUrl: queueUrl, /* required */
    ReceiptHandle: receiptHandle /* required */
  };

  console.log('Removing record from ', queueUrl, 'with params', deleteParams);    
  await sqs.deleteMessage(deleteParams).promise();
} else {
  /* any record that ends up here, are never seen again :( */
  console.log('Keeping record in', eventSourceARN);
}

What do 🙁 ?!?!11

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

otherwise I do nothing with the receiptHandle which I think should then keep the message in the queue

That’s not now it works:

Lambda polls the queue and invokes your Lambda function synchronously with an event that contains queue messages. Lambda reads messages in batches and invokes your function once for each batch. When your function successfully processes a batch, Lambda deletes its messages from the queue.

Method 2

When an AWS Lambda function is triggered from an Amazon SQS queue, all activities related to SQS are handled by the Lambda service. Your code should not call any Amazon SQS functions.

The messages will be provided to the AWS Lambda function via the event parameter. When the function successfully exits, the Lambda service will delete the messages from the queue.

Your code should not be calling DeleteMessage().

If you wish to signal that some of the messages were not successfully processed, you can use a partial batch response to indicate which messages were successfully processed. The AWS Lambda service will then make the unsuccessful messages available on the queue again.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

Leave a Reply