Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda processing same SNS event multiple times?

I have an AWS Lambda function configured to process SNS events from a single topic. When the function runs it will potentially send out some other notifications and call context.succeed, or context.fail if some error occurs. The problem is the same SNS event seems to be invoking the Lambda multiple times. Looking at the CloudWatch logs I see

START RequestId: cd7afdf8-2816-11e6-bca2-6f2e3027c5e1 Version: $LATEST

Which eventually ends

END RequestId: cd7afdf8-2816-11e6-bca2-6f2e3027c5e1 REPORT RequestId: cd7afdf8-2816-11e6-bca2-6f2e3027c5e1 ...

Immediately followed in the same log by a start for the exact same RequestID

START RequestId: cd7afdf8-2816-11e6-bca2-6f2e3027c5e1 Version: $LATEST

Looking into CloudWatch at the topic sending this SNS Event it seems to only be Publishing and Delivering only one even as I had expected, so it seems to be a Lambda-side problem. Does anyone know of any reason an event might be triggering my lambda multiple times like this?

Edit: I've noticed that this seems to be happening when the lambda receives a failure. I don't see any sort of retry configuration on the lambda and wouldn't expect it to be behaving this way by default.

like image 1000
Squirrel Avatar asked Jun 01 '16 20:06

Squirrel


2 Answers

From Amazon lambda FAQs page https://aws.amazon.com/lambda/faqs/

Q: What happens if my Lambda function fails during processing an event?

On failure, Lambda functions being invoked synchronously will respond with an exception. Lambda functions being invoked asynchronously are retried at least 3 times, after which the event may be rejected. Events from Amazon Kinesis streams and Amazon DynamoDB streams are retried until the Lambda function succeeds or the data expires. Kinesis and DynamoDB Streams retain data for 24 hours.

like image 121
Shibashis Avatar answered Sep 21 '22 19:09

Shibashis


I had a similar issue with a lambda cron job function. I needed to send a request to a service/api that runs for a couple of seconds before it can return the first byte/response (no response processing needed), so my fix was like the following:

exports.handler = (event, context, callback) => {
// TODO implement

var https = require("https");
token = "xxxxxxxx";

var options = {
    host: "api.xxxxx.com",
    path: "/manage/cronjob/video",
    method: "GET",
    headers: {
        "Content-Type": "application/json",
        "Authorization": "Bearer "+token
    }
};

var req = https.request(options);
req.write("");
req.end();

//add timeout for context.done()
setTimeout(function(){
    context.done();
    callback(null, 'Hello from Lambda');
},1000); //This timeout should be lower than the lambda's timeout };

In this is example, we have an explicit callback to force the lambda exit, before the function gets a timeout error & triggers a retry for another 2 times

Hope it helps

like image 21
Nourdine Alouane Avatar answered Sep 21 '22 19:09

Nourdine Alouane