Q: will Mangum run lifespan multiple times? #211
-
I'm trying to run fastapi app with custom lifespan-aware middleware. The error is: File "my-middleware-that-tries-to-honour-lifespan.py", line 98, in __call__
await self.under.__aenter__()
File "/usr/local/lib/python3.10/contextlib.py", line 197, in __aenter__
del self.args, self.kwds, self.func
AttributeError: args (That's Py 3.10 error, the exception is a bit misleading: https://bugs.python.org/issue45996) The cause is that my middleware accepts an instance of an In the FastAPI/starlette/uvicorn combo, there's a case (maybe even an assumption) that startup and shutdown are ran only once. After that the entire However, it seems, as if |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments
-
The startup and shutdown events are only expected to run once. How are you running Mangum using 3.10? It currently only supports the latest Python version that AWS Lambda supports (3.9). I’ll move this to discussions because it doesn’t seem like a bug specifically in Mangum at this point. |
Beta Was this translation helpful? Give feedback.
-
I believe I've also run into this. For every request, mangum runs the startup event, then the handler, then the shutdown event. For applications with expensive startup tasks, this is wasteful and does not match my understanding of ASGI lifespan semantics. Consider the following FastAPI application: import asyncio
from fastapi import FastAPI
from mangum import Mangum
app = FastAPI()
@app.on_event("startup")
async def on_startup():
print("> Starting up")
await asyncio.sleep(3) # Simulate expensive startup tasks
@app.get("/")
async def read_root():
print("> Handling request")
return "Hello World!"
@app.on_event("shutdown")
async def on_shutdown():
print("> Shutting down")
handler = Mangum(app) When run via Uvicorn it behaves as expected.
The server takes some time to start up, but responds promptly to individual requests. However, when run using Mangum with Lambda and API Gateway, this is not the case. The Lambda must be configured with a longer timeout as the 3 seconds at startup is counted against the request rather than as Init time.
Notice the first request has an Init Duration of 492.79 ms to load the runtime. The 3000ms Unfortunately it seems like the only way to implement this correctly is to register an extension (https://docs.aws.amazon.com/lambda/latest/dg/runtimes-extensions-api.html) in order to receive and process the shutdown event. My current workaround is to disable Mangum's lifespan handling and run my start function manually: handler = Mangum(app, lifespan="off")
if "AWS_EXECUTION_ENV" in os.environ:
loop = asyncio.get_event_loop()
loop.run_until_complete(app.router.startup()) This is sufficient for my use case because I do not require any shutdown logic. |
Beta Was this translation helpful? Give feedback.
-
I am having the same trouble as evanandrews-xrd. In my case I am using I'm going to try out his solution. |
Beta Was this translation helpful? Give feedback.
-
lifespan will be run on each invocation from mangum import Mangum
from fastapi import FastAPI
from starlette.requests import Request
app = FastAPI()
app.state.start_count = 0
app.state.off_count = 0
@app.get("/check")
def landing(request: Request):
return {
"start": request.app.state.start_count,
"end": request.app.state.off_count,
}
@app.on_event("startup")
async def startup_event():
"""Connect to database on startup."""
print("Startup")
app.state.start_count += 1
@app.on_event("shutdown")
async def shutdown_event() -> None:
"""Close database connection."""
print("Shutdown")
app.state.off_count += 1
handler = Mangum(app, lifespan="auto")
Solution provided by @evanandrews-xrd works and it also seems to be that lambda-extension is the only proper solution :-( |
Beta Was this translation helpful? Give feedback.
-
Hi All Also seeing this issue, Should this not be considered a bug? as lifespan should be for the lifetime of the application, not for a request Thanks |
Beta Was this translation helpful? Give feedback.
I believe I've also run into this.
For every request, mangum runs the startup event, then the handler, then the shutdown event. For applications with expensive startup tasks, this is wasteful and does not match my understanding of ASGI lifespan semantics.
Consider the following FastAPI application: