Dead Letter Queue SNS DLQ
RE CS:
There is a difference in triggering a Lambda from SNS (topic) and SQS (queue). When using SQS and an error occurs, the original message is simply put back on the queue. After the visibility timeout is exceeded, the queue will dump the message on a DLQ (depending on configuration). No error context is provided and this could take several minutes, depending on the visibility timeout. When a Lambda processes a message from SNS and a DLQ is configured on the lambda, the message is immediately put on the DLQ and the message on the DLQ has the error context. This seems like the preferable approach, although not as scalable as a SQS system for extreme message volume. But, I don’t think the systems we have worked on so far would exceed the SNS system capacity.
So there is a difference in triggering a lambda from SQS and SNS. I think SNS has the advantage in terms of responsiveness and error handling. Here is a sample error message dropped on the DLQ when triggered by SNS:
{
"version": "1.0",
"timestamp": "2023-06-16T17:57:05.098Z",
"requestContext": {
"requestId": "16d47381-f576-447f-bd38-1a7f864bda89",
"functionArn": "arn:aws:lambda:us-west-2:118234403147:function:cslater-dev-echofish-CruiseSplitterLambdaSt-Lambda-E40cQxCJ7Kz5:$LATEST",
"condition": "RetriesExhausted",
"approximateInvokeCount": 1
},
"requestPayload": {
"Records": [
{
"EventSource": "aws:sns",
"EventVersion": "1.0",
"EventSubscriptionArn": "arn:aws:sns:us-west-2:118234403147:cslater-dev-echofish-cruise-splitter-done:427c7ca3-be8f-4a02-8da3-3486e94699d6",
"Sns": {
"Type": "Notification",
"MessageId": "3a7f4179-c464-5a83-8376-1c7f60ceb0ed",
"TopicArn": "arn:aws:sns:us-west-2:118234403147:cslater-dev-echofish-cruise-splitter-done",
"Subject": null,
"Message": "{\"cat\":\"dog\"}",
"Timestamp": "2023-06-16T17:56:58.867Z",
"SignatureVersion": "1",
"Signature": "ayDuhCrpveJ7iY0IDIJ5yz98eGeAVimFnEfyiefR8jntmLnyWOc7RDu38hMDPjvmjTfydsuN99t98XT4e8jG9gk4ybCZ1W0i6/3xOes8UVvqu8RhjBLPMKprVEnzVJnMIA0HSzmACVoPvqcY82dSEUeyHmYC7oeKabvBOPu+G6qwoE5EggW8IP1FB+DYps1KNh2Ovxy6I/jCZ+bSJcjTMSJpuloGmjR2qeSnKJxxPvTa3HtrpbYQSXNcqD8ZusDFlE9KHqTNX/kHugbPPgML0kYIXBOD/Tzy9CbSTNF53H2i9jFNb1YSsHNerjxONSsb0pwA0lRQiQJIEc3DBP3pUg==",
"SigningCertUrl": "https://sns.us-west-2.amazonaws.com/SimpleNotificationService-01d088a6f77103d0fe307c0069e40ed6.pem",
"UnsubscribeUrl": "https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-west-2:118234403147:cslater-dev-echofish-cruise-splitter-done:427c7ca3-be8f-4a02-8da3-3486e94699d6",
"MessageAttributes": {
}
}
}
]
},
"responseContext": {
"statusCode": 200,
"executedVersion": "$LATEST",
"functionError": "Unhandled"
},
"responsePayload": {
"errorMessage": "The bucket is in this region: us-east-1. Please use this region to retry the request (Service: Amazon S3; Status Code: 301; Error Code: PermanentRedirect; Request ID: VDNTZR33KMDWXK0V; S3 Extended Request ID: fFQrSirLJ2OyDX8g1e8/3zPekrPGY5RFJFiBswf8Jm9NHRoD5E97fM2wB0ciDkH+t0qyWjGK+jI=; Proxy: null)",
"errorType": "com.amazonaws.services.s3.model.AmazonS3Exception",
"stackTrace": [
"com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1879)",
"com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleServiceErrorResponse(AmazonHttpClient.java:1418)",
"com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1387)",
"com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1157)",
"com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:814)",
"com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:781)",
"com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:755)",
"com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:715)",
"com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:697)",
"com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:561)",
"com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:541)",
"com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:5470)",
"com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:5417)",
"com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:5411)",
"com.amazonaws.services.s3.AmazonS3Client.listObjects(AmazonS3Client.java:929)",
"com.amazonaws.services.s3.AmazonS3Client.listObjects(AmazonS3Client.java:903)",
"edu.colorado.cires.cmg.echofish.data.s3.S3OperationsImpl.listObjects(S3OperationsImpl.java:70)",
"edu.colorado.cires.cmg.echofish.aws.lambda.cruisesplit.CruiseSplitterLambdaHandler.getRawFiles(CruiseSplitterLambdaHandler.java:71)",
"edu.colorado.cires.cmg.echofish.aws.lambda.cruisesplit.CruiseSplitterLambdaHandler.handleRequest(CruiseSplitterLambdaHandler.java:46)",
"edu.colorado.cires.cmg.echofish.aws.lambda.cruisesplit.CruiseSplitterLambda.handleRequest(CruiseSplitterLambda.java:47)",
"java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
"java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)",
"java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)",
"java.base/java.lang.reflect.Method.invoke(Unknown Source)"
]
}
}And that error was immediately put on the DLQ. When using SQS, all that you get on the DLQ is the original message and that message doesn’t show up until after the visibility timeout.
J: I’m not sure I understand how one would configure a DLQ on an SNS topic or on a Lambda itself. I’ve only used DLQs on the SQS queues.
C: There is no DLQ on a SNS topic. However you can add one on a Lambda that is fed by a SNS topic
C: Here is the CF template for that:
C: The destination can be a variety of endpoints. This uses a topic, but it could be a queue
C: It is available in the console too, under the destination config
C: This does not work if the Lambda is fed by SQS though
C: It needs to be asynchronous. SQS invocations are synchronous.
Testing with one sns topic into lambda and two sns topics out (one success, one DLQ):
With lambda code:
Last updated
Was this helpful?