jordaneremieff / mangum

AWS Lambda support for ASGI applications
https://mangum.io/
MIT License
1.67k stars 119 forks source link

Dealing with long running client #320

Closed zhavir closed 3 months ago

zhavir commented 4 months ago

Hello, do you know which is the beast way to deal with a long-running client? I'd like to use boto3 client within an api call, but it is taking forever every time to setup the session and making the call. Any suggestion? where is the best place where to initialize the boto3 session?

25thbamofthetower commented 4 months ago

AWS has docs about where to place it. It's usually outside of the Lambda handler function. It's usually the first search results. But I think what you're seeing might be the Lambda coldstart.

zhavir commented 4 months ago

yes, more or less. I've put my client init outside the handler. But seems like that, even so, the first call to SNS (that is my case) is taking forever (3.5 secs). Afterward, consecutive calls are taking 200 ms. Interestingly, I've tried to set up a CloudWatch event that is always warming the lambda function (more or less), with this trick I was able to decrease the timing to 1.2 secs on the first call, consecutive calls are still taking 200 ms. To reduce the time also for the first call I was forced to call the list topic right after the initialization of the Boto client

nitsujri commented 3 months ago

To reduce the time also for the first call I was forced to call the list topic right after the initialization of the Boto client

This is cold start problem, right? After you deploy your AWS Lambda container? When you deploy a new version, it takes 3.5 to 5 seconds to cold start and fully answer a client?

If it is, we deal with this problem via blue/green deployments with CodeDeploy. For us, we use the CDK, specifically

  1. aws_sam.CfnFunction.
    • This is not lambda.cfnfunction.
  2. This allows us to use the pre-deployment Validation. via deploymentPreference: {hooks: { preTraffic: ... }}
  3. preTraffic is the same container but with a different entrypoint.
    • The entry point is a special "pre-warming" hook that fires a direct lambda call to the main one.
    • We call in parallel 5x (synchronous) to the "incoming" version with a special params.
    • The special param is a code path that effectively calls print(User.objects.count()). This makes the container reach out to the DB, helps test and makes real calls+codepaths.
    • The special codepath also has a sleep of 0.25-0.4 random, simply helps make 5x parallel containers prewarmed.
  4. Once all the parallel direct lambda calls have returned, we return the preTraffic hook w/ a positive result. If any prewarm fails, we fail the preTraffic.

This way you can pre-warm the new version and only switch traffic to the new version after the cold start has been "dealt with". It has the benefit of testing all the way to a simple DB call so in case there's a failure the new version never gets switched in.

zhavir commented 3 months ago

thank you so much @nitsujri! it worked for me