Add startup/shutdown handlers to FastAPI app with lifespan API

3.3k views Asked by At

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

1

There are 1 answers

1
Falko On BEST ANSWER

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.