39
votes

I am using aws lambda function to convert uploaded wav file in a bucket to mp3 format and later move file to another bucket. It is working correctly. But there's a problem with triggering. When i upload small wav files,lambda function is called once. But when i upload a large sized wav file, this function is triggered multiple times.

I have googled this issue and found that it is stateless, so it will be called multiple times(not sure this trigger is for multiple upload or a same upload).

https://aws.amazon.com/lambda/faqs/

Is there any method to call this function once for a single upload?

4
"not sure this trigger is for multiple upload or a same upload" ... doesn't it seem like that should be the first thing you should work toward figuring out? Statelessness has nothing to do with it. Examine the actual event content, create a log of what you are receiving in the S3 event and store it for review, and the explanation should become obvious. Most likely, behavior in whatever you are using to originally upload the object is doing more S3 operations than you realize.Michael - sqlbot
You need to expand this question with more specific information. Ideally a code sample.adamkonrad
Sounds like the upload is being broken into parts. You'll want to create an event specify that the event is only executed on s3:ObjectCreated:CompleteMultiPartUpload, this tutorial shows how to do that just replace s3:ObjectCreated:* with s3:ObjectCreated:CompleteMultiPartUpload.philippjfr

4 Answers

38
votes

Short version: Try increasing timeout setting in your lambda function configuration.

Long version:

I guess you are running into the lambda function being timed out here.

S3 events are asynchronous in nature and lambda function listening to S3 events is retried atleast 3 times before that event is rejected. You mentioned your lambda function is executed only once (with no error) during smaller sized upload upon which you do conversion and re-upload. There is a possibility that the time required for conversion and re-upload from your code is greater than the timeout setting of your lambda function.

Therefore, you might want to try increasing the timeout setting in your lambda function configuration.

By the way, one way to confirm that your lambda function is invoked multiple times is to look into cloudwatch logs for the event id (67fe6073-e19c-11e5-1111-6bqw43hkbea3) occurrence -

START RequestId: 67jh48x4-abcd-11e5-1111-6bqw43hkbea3 Version: $LATEST

This event id represents a specific event for which lambda was invoked and should be same for all lambda executions that are responsible for the same S3 event.

Also, you can look for execution time (Duration) in the following log line that marks end of one lambda execution -

REPORT RequestId: 67jh48x4-abcd-11e5-1111-6bqw43hkbea3  Duration: 244.10 ms Billed Duration: 300 ms Memory Size: 128 MB Max Memory Used: 20 MB

If not a solution, it will at least give you some room to debug in right direction. Let me know how it goes.

8
votes

Any event Executing Lambda several times is due to retry behavior of Lambda as specified in AWS document.

Your code might raise an exception, time out, or run out of memory. The runtime executing your code might encounter an error and stop. You might run out concurrency and be throttled.

There could be some error in Lambda which makes the client or service invoking the Lambda function to retry.

Use CloudWatch logs to find the error and resolving it could resolve the problem.

I too faced the same problem, in my case it's because of application error, resolving it helped me.

Recently AWS Lambda has new property to change the default Retry nature. Set the Retry attempts to 0 (default 2) under Asynchronous invocation settings.

4
votes

The context object contains information on which request ID you are currently handling. This ID won't change even if the same event fires multiple times. You could save this ID for every time an event triggers and then check that the last ID you handled isn't the same as the current one.

Here's my final code to fix this issue (NodeJS with MongooseJS database handler):

exports.handler = function(event, context, lambdaCallback) {        
    Events.findOneAndUpdate(
        { name: 'some-event-name' }, 
        { lastRequestId: context.awsRequestId }).then(function(event) {
        
        if(event.lastRequestId == context.awsRequestId) {
            return;
        }

        /* Run the actual job */
        ...
    });
}

Hope this helps!

1
votes

In the Lambda Configuration look for "Asynchronous invocation" there is an option "Retry attempts" that is the maximum number of times to retry when the function returns an error.

Here you can also configure Dead-letter queue service