Discover how a simple context manager can save your app from hidden crashes and resource leaks!
Why Lifespan context manager in FastAPI? - Purpose & Use Cases
Start learning this pattern below
Jump into concepts and practice - no test required
Imagine you have a web app that needs to connect to a database and start background tasks every time it runs. You try to open connections and start tasks manually in many places in your code.
Doing this manually means you might forget to close connections or stop tasks properly. This can cause your app to slow down, crash, or leak resources without clear errors.
The lifespan context manager in FastAPI lets you define startup and shutdown actions in one place. It automatically runs your setup code when the app starts and cleanup code when it stops, keeping things neat and safe.
async def startup(): await connect_db() async def shutdown(): await disconnect_db() app.add_event_handler('startup', startup) app.add_event_handler('shutdown', shutdown)
from fastapi import FastAPI app = FastAPI() @app.lifespan async def lifespan(app): await connect_db() yield await disconnect_db()
This lets your app manage resources cleanly and reliably, so it runs smoothly without leaks or crashes.
Think of a coffee machine that automatically starts heating water when turned on and cleans itself when turned off. The lifespan context manager does the same for your app's resources.
Manual resource management is error-prone and messy.
Lifespan context manager centralizes startup and shutdown logic.
It ensures clean, reliable app behavior and resource use.
Practice
lifespan context manager in a FastAPI application?Solution
Step 1: Understand the role of lifespan context manager
The lifespan context manager is designed to run code at the start and end of the FastAPI app lifecycle.Step 2: Identify its main use
It is used to set up resources like database connections when the app starts and clean them up when the app stops.Final Answer:
To run setup code when the app starts and cleanup code when it stops -> Option DQuick Check:
Lifespan manages startup and shutdown code = A [OK]
- Confusing lifespan with route handling
- Thinking lifespan manages HTTP requests
- Assuming lifespan handles user sessions
Solution
Step 1: Recall lifespan signature
The lifespan function must be async and accept the app parameter to manage startup and shutdown.Step 2: Confirm use of yield
Usingyieldinside the async function allows running code before and after the yield for startup and shutdown.Final Answer:
async def lifespan(app): yield -> Option AQuick Check:
Async + app param + yield = A [OK]
- Forgetting async keyword
- Missing app parameter
- Using return instead of yield
async def lifespan(app):
print('Starting app')
yield
print('Stopping app')Solution
Step 1: Understand yield in lifespan
The code beforeyieldruns at startup, and code afteryieldruns at shutdown.Step 2: Match prints to lifecycle events
So 'Starting app' prints when app starts, and 'Stopping app' prints when app stops.Final Answer:
'Starting app' prints on start, 'Stopping app' prints on shutdown -> Option BQuick Check:
Code before yield = start, after yield = stop [OK]
- Thinking both prints run immediately
- Assuming yield blocks all prints
- Confusing start and stop timing
async def lifespan(app):
print('Starting')
return
print('Stopping')Solution
Step 1: Identify use of return instead of yield
The lifespan function must useyieldto separate startup and shutdown code.Step 2: Understand effect of return
Usingreturnexits the function immediately, so shutdown code after it never runs.Final Answer:
Using return instead of yield prevents shutdown code from running -> Option CQuick Check:
Return exits early; yield separates start/stop [OK]
- Confusing return and yield in async functions
- Ignoring that shutdown code runs after yield
- Assuming print statements cause errors
Solution
Step 1: Confirm async function with app parameter
The lifespan function must be async and accept the app parameter to store the db connection.Step 2: Check order of operations
Connect to the database before yield, store it on app.state, then close it after yield.Step 3: Verify correct use of await and yield
Await connect_db and db.close, yield separates startup and shutdown code.Final Answer:
async def lifespan(app): db = await connect_db() app.state.db = db yield await db.close() -> Option AQuick Check:
Async + app param + yield + await connect/close = D [OK]
- Placing yield before storing db connection
- Missing async or await keywords
- Not passing app parameter to lifespan
