Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does AWS Lambda charge for the time spent initializing code?

If my Lambda function written in Python takes 1.8 seconds to initialize (during a cold start) and 400 ms to execute, am I charged for the 400 ms execution time or the entire 2.2 seconds of initialization + execution time?

From X-Ray, I see:

AWS X-Ray trace

From CloudWatch logs, I see:

Duration: 404.42 ms Billed Duration: 500 ms Memory Size: 448 MB Max Memory Used: 113 MB

What I understand from this is that I was billed for 500ms of execution time, so does that mean code initialization (e.g. importing stuff) is free?

like image 427
Vinayak Avatar asked Mar 29 '19 07:03

Vinayak


People also ask

How does AWS Lambda charge users?

AWS Lambda is charging its users by the number of requests for their functions and by the duration, which is the time the code needs to execute. When your code starts running in response to an event, AWS Lambda counts a request. It will charge the total number of requests across all of the functions used.

How does AWS Lambda count request time?

When your code starts running in response to an event, AWS Lambda counts a request. It will charge the total number of requests across all of the functions used. Duration is calculated by when your code started executing until it returns or is terminated, rounded up to the closest 1 millisecond.

How long does it take for AWS Lambda to deploy?

Deployment times may vary with the size of your code, but AWS Lambda functions are typically ready to call within seconds of upload. Q: Can I use my own version of a supported library?

Does AWS Lambda have maintenance windows or scheduled downtimes?

AWS Lambda is designed to use replication and redundancy to provide high availability for both the service itself and for the Lambda functions it operates. There are no maintenance windows or scheduled downtimes for either. Q: Do my AWS Lambda functions remain available when I change my code or its configuration?


Video Answer


1 Answers

So I decided to try and figure it out myself with a little experiment. I created a Lambda function using Python 2.7 with 128 MB of RAM, timeout of 15 seconds and active tracing enabled. I modified the sample code to add a 10 second sleep right after the import statement:

print "starting import"
import json
from time import sleep
sleep(10)
print "calling handler"

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

Since the Lambda started cold, I saw this in the X-ray output: AWS X-ray output - cold start

And I saw this in CloudWatch logs:

22:06:47 starting import
22:06:57 calling handler
22:06:58 START RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Version: $LATEST
22:06:58 starting import
22:07:08 calling handler
22:07:08 END RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
22:07:08 REPORT RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Duration: 10022.57 ms   Billed Duration: 10100 ms Memory Size: 128 MB   Max Memory Used: 19 MB

The function actually ran TWICE. After sleeping for 10 seconds the first time, it re-started when the handler method was called, essentially taking 20 seconds to finish execution but billing me for 10 seconds.

I ran it again, this time a warm-start and I got this:

X-ray output (warm start): AWS X-ray output - warm start

CloudWatch logs (warm start):

22:23:16 START RequestId: yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy Version: $LATEST
22:23:16 END RequestId: yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
22:23:16 REPORT RequestId: yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy Duration: 6.97 ms   Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 29 MB

Nothing suspicious there. I increased the function memory to 192 MB, saved it and reverted it back to 128 MB and saved it again to ensure that it'd start cold again and invoked it once again. The output of X-ray was the same as before but CloudWatch logs had something interesting:

22:30:13 starting import
22:30:24 START RequestId: zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz Version: $LATEST
22:30:24 starting import
22:30:34 calling handler
22:30:34 END RequestId: zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz
22:30:34 REPORT RequestId: zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz Duration: 10010.85 ms   Billed Duration: 10100 ms Memory Size: 128 MB   Max Memory Used: 19 MB

It seems while my code was in the middle of sleeping for 10 seconds, Lambda cut it off and re-started it. The execution time was again 20 seconds but I was billed for 10 seconds. So I thought what if instead of 1 sleep statement, I add 15 one second sleeps?

Updated code:

print "starting import"
import json
from time import sleep
for i in range(1, 16):
    sleep(1)
    print "completed {}th sleep".format(i)

print "calling handler"
def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

The function timed out!

X-ray output: enter image description here

CloudWatch logs:

22:51:54 starting import
22:51:55 completed 1th sleep
22:51:56 completed 2th sleep
22:51:57 completed 3th sleep
22:51:58 completed 4th sleep
22:51:59 completed 5th sleep
22:52:00 completed 6th sleep
22:52:01 completed 7th sleep
22:52:02 completed 8th sleep
22:52:03 completed 9th sleep
22:52:04 START RequestId: 11111111-1111-1111-1111-111111111111 Version: $LATEST
22:52:04 starting import
22:52:05 completed 1th sleep
22:52:06 completed 2th sleep
22:52:07 completed 3th sleep
22:52:08 completed 4th sleep
22:52:09 completed 5th sleep
22:52:10 completed 6th sleep
22:52:11 completed 7th sleep
22:52:12 completed 8th sleep
22:52:13 completed 9th sleep
22:52:14 completed 10th sleep
22:52:15 completed 11th sleep
22:52:16 completed 12th sleep
22:52:17 completed 13th sleep
22:52:18 completed 14th sleep
22:52:19 END RequestId: 11111111-1111-1111-1111-111111111111
22:52:19 REPORT RequestId: 11111111-1111-1111-1111-111111111111 Duration: 15015.16 ms   Billed Duration: 15000 ms Memory Size: 192 MB   Max Memory Used: 19 MB
22:52:19
2019-03-29T22:52:19.621Z 11111111-1111-1111-1111-111111111111 Task timed out after 15.02 seconds
22:52:19 starting import
22:52:20 completed 1th sleep
22:52:21 completed 2th sleep
22:52:22 completed 3th sleep
22:52:23 completed 4th sleep
22:52:24 completed 5th sleep
22:52:25 completed 6th sleep
22:52:26 completed 7th sleep
22:52:27 completed 8th sleep
22:52:28 completed 9th sleep
22:52:29 completed 10th sleep

It actually executed for 25.8 seconds but then timed out and billed me for 15 seconds. The code that executes before the handler is called ran for about 9 seconds then Lambda cut it off and re-started the function but didn't finish and ultimately timed out after 25.8 seconds. If I increase the Lambda timeout to 16 seconds, it finished executing in 25.8 seconds (as shown in X-Ray) and billed me for 15100 ms.

So this leads me to believe that if the handler function isn't called within about 9-10 seconds after initialization, Lambda will restart the function. So what if the code initialization takes less than 10 seconds?

Updated code:

print "starting import"
import json
from time import sleep
for i in range(1, 10):
    sleep(1)
    print "completed {}th sleep".format(i)

print "calling handler"
def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

I ran this function cold for about 10 times and my billed duration was always 100 ms. I even changed my lambda timeout to 1 second and it still finished executing successfully!

X-Ray output: enter image description here

CloudWatch logs:

23:23:43 starting import
23:23:44 completed 1th sleep
23:23:45 completed 2th sleep
23:23:46 completed 3th sleep
23:23:47 completed 4th sleep
23:23:48 completed 5th sleep
23:23:49 completed 6th sleep
23:23:50 completed 7th sleep
23:23:51 completed 8th sleep
23:23:52 completed 9th sleep
23:23:52 calling handler
23:23:52 START RequestId: 22222222-2222-2222-2222-222222222222 Version: $LATEST
23:23:52 END RequestId: 22222222-2222-2222-2222-222222222222
23:23:52 REPORT RequestId: 22222222-2222-2222-2222-222222222222 Duration: 0.73 ms   Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 44 MB

As Steve HOUEL rightfully pointed out, this leads me to believe that Lambda won't charge you for the time it takes to initialize your code (e.g. importing stuff) as long as it finishes in about 9 seconds. However, if it takes longer than that, Lambda re-starts your function and assuming you set a large enough timeout, function execution effectively takes 10 seconds + regular cold start execution time but you are still billed for just the cold start execution time without the added 10 seconds.

like image 187
Vinayak Avatar answered Jan 03 '23 19:01

Vinayak