Consider a FastAPI using the lifespan
parameter like this:
def lifespan(app):
print('lifespan start')
yield
print('lifespan end')
app = FastAPI(lifespan=lifespan)
Now I want to register a sub app with its own lifecycle functions:
app.mount(mount_path, sub_app)
How can I register startup/shutdown handlers for the sub app?
All solutions I could find either require control over the lifespan
generator (which I don't have) or involve deprecated methods like add_event_handler
(which doesn't work when lifespan
is set).
Update Minimal reproducible example:
from fastapi import FastAPI
# --- main app ---
def lifespan(_):
print("startup")
yield
print("shutdown")
app = FastAPI(lifespan=lifespan)
@app.get("/")
async def root():
return {"message": "Hello World"}
# --- sub app ---
sub_app = FastAPI()
@sub_app.get("/")
async def sub_root():
return {"message": "Hello Sub World"}
app.mount("/sub", sub_app)
app.on_event("startup")(lambda: print("sub startup")) # doesn't work
app.on_event("shutdown")(lambda: print("sub shutdown")) # doesn't work
Run with: uvicorn my_app:app --port 8000
I found a solution, but I'm not sure if I like it... It accesses the existing lifespan generator via app.router.lifespan_context
and wraps it with additional startup/shutdown commands:
from contextlib import asynccontextmanager
...
main_app_lifespan = app.router.lifespan_context
@asynccontextmanager
async def lifespan_wrapper(app):
print("sub startup")
async with main_app_lifespan(app) as maybe_state:
yield maybe_state
print("sub shutdown")
app.router.lifespan_context = lifespan_wrapper
Output:
INFO: Waiting for application startup.
sub startup
startup
INFO: Application startup complete.
...
INFO: Shutting down
INFO: Waiting for application shutdown.
shutdown
sub shutdown
INFO: Application shutdown complete.