Miserlou / Zappa

Serverless Python
https://blog.zappa.io/
MIT License
11.89k stars 1.2k forks source link

Slow Cold Starts Becasue App Code Loaded Inside of Lambda Handler #1974

Open ElMoselYEE opened 4 years ago

ElMoselYEE commented 4 years ago

Context

For my Flask + Zappa setup, I noticed that the app code gets loaded inside of the lambda_handler. This prevents us from taking advantage of the bumped up horsepower that Amazon providers for free during the initialization phase.

self.app_module = importlib.import_module(self.settings.APP_MODULE)

By hand-modding my code to load my app outside of Zappa's lambda_handler middleware, I was able to reduce my cold start time from 7 seconds down to 1 second.

Expected Behavior

Take advantage of performance boost for code outside of Lambda handler by importing app code before lambda_handler is reached.

Actual Behavior

App code imported within Lambda handler, which wastes valuable time.

Possible Fix

I don't have one

Steps to Reproduce

  1. My Flask app is available at app.py
  2. Use zappa package to create a .zip file, deploy it manually
  3. Run Function: takes 7 seconds.
  4. Open up .zip file and add "import app" to line 2 of handler.py
  5. Deploy function manually
  6. Run function: takes 1 second.

I can repeat this process and the timing is very repeatable.

Your Environment

bgrommes commented 4 years ago

I would like this feature as well so that I can perform expensive initialization when the Lambda container is first initialized instead of when the function is first called. This would allow me to have all Lambda function calls avoid initialization costs when combined with the new Lambda Provisioned Concurrency feature.

bgrommes commented 4 years ago

I should also add that to hack this feature into the existing version of Zappa instead of an explicit "import app" statement I added LambdaHandler() at the end of handler.py. This approach forces the lazy init of LambdaHandler (which includes importing the app module if applicable) which normally happens on the first call to the lambda handler function.

What is/was the rationale for lazy loading LambdaHandler?

alecl commented 4 years ago

Using a framework that has slow init time to begin with like Connexion this is the difference between subsecond or 7+ second start times.

If there's an important reason for this lazy load to be on by default can it at least be an overridable option to not do it?

WorkDuringNight commented 4 years ago

I got this issue, too.

After adding LambdaHandler() to the bottom of handler.py, it seems to resolve the problem. Wondering if that is the right fix.

jneves commented 3 years ago

How are you measuring the cold starts? It seems like you're moving the initialisation into the importing phase of the code, so I wouldn't expect it to be faster on a cold start, as the same code is still running, but the result seems really interesting (and it wouldn't be the first time I was wrong).

ElMoselYEE commented 3 years ago

Lambda actually provides more resources than you provision during cold start initialization. So code that runs during this phase will get run more quickly. As you can see from my numbers, in some cases the difference in execution time can be drastic.

omkarubale commented 9 months ago

I don't see the code from #982 in the latest version. Was this reverted or superseded by another feature to solve this issue?

souravjamwal77 commented 9 months ago

Hi @omkarubale, The new Zappa library is here