amazon-web-serviceslambdaamazon-sqsdead-letter

Why is SQS not sending message to dead letter queue until after visibility timeout?


I have an AQS SQS configured as a trigger for a Lambda. This SQS is also configured to send unprocessable messages to a Dead Letter Queue I setup. I have set the Maximum Receives to 1 as that is the minimum and the visibility timeout on my trigger queue to 5 minutes. My intent is to have 0 reprocessing. If the message from the trigger queue fails I want it to go to the DLQ right away. My understanding was that if an exception was thrown in my lamdba that it would send it to the DLQ immediately if the Maximum Receives was set to lowest (1 in this case), regardless of the visibility timeout. However it seems even if I throw an exception, the message still waits the full 5 minutes before then moving to the DLQ. Is there any way to get it to move immediately on exception regardless of visibility timeout? Thanks.


Solution

  • "My understanding was that if an exception was thrown in my lamdba that it would send it to the DLQ immediately" - No.

    SQS does not know about your lambda (or any other processing for that matter) failing or throwing an exception. Only after the visibility timeout expires can SQS consider the message processing to have failed and only then can it put the message into the DLQ.

    SQS does not know or care how its consumers handle the message, if they e.g. retry internally, always delete the message at the last possible second, never delete a message, delete the message before actually working on it, etc. And therefore SQS cannot take any actions when the consumers fail because SQS simply does not know what a consumer failing looks like. And it is also not clear to SQS if anything actually failed, maybe the consumer simply took too long to process the message, SQS does not care.


    And no, you cannot reasonably change that behaviour. You might be able to change the visibility timeout of the one message manually right before your lambda actually throws the exception (see ChangeMessageVisibility) or you could delete the message and manually send it to the DLQ (very bad idea / practise). Both approaches require manual work and more importantly require your lambda to be aware of its own exception, catch all exceptions, do some SQS stuff and then rethrow the exception - this is guaranteed to go wrong in some way...