**Async Dependency Lifecycles in FastAPI: When Generators Go Wrong**
Gotcha: Unclosed Async Generators
⚠️ Async generator deps can leak resources if not closed; use asynccontextmanager + Depends for clean, per‑request lifecycles.
🎯 System Scenario & Requirements
System Goal
⚠️ Async generator deps can leak resources if not closed; use asynccontextmanager + Depends for clean, per‑request lifecycles.
Actors & Components
- Application or API tier
- Core service under design
- Operator or SRE observer
Functional Requirements
- TLDR: ⚠️ Async generator deps can leak resources if not closed; use asynccontextmanager + Depends for clean, per‑request lifecycles.
- In a FastAPI app, it’s tempting to write a dependency that yields a DB session via an async generator: If the dependency is used in many routes, the Session objects pile up because FastAPI only closes the generator when…
- Forgetting that block means connections stay open, eventually exhausting the pool.
Constraints & Assumptions
- Constraints are derived from the rebuilt scenario stages.
⚡ Execution Stages & Decision Trace
Stage 1 — The Solution: `asynccontextmanager` + `Depends`
Wrap the generator in asynccontextmanager from contextlib .
FastAPI automatically calls the cleanup when the request finishes: FastAPI injects the yielded session and ensures the finally block runs even if the endpoint raises.
Deep Dive
Scenario context
⚠️ Async generator deps can leak resources if not closed; use asynccontextmanager + Depends for clean, per‑request lifecycles.
In a FastAPI app, it’s tempting to write a dependency that yields a DB session via an async generator:
If the dependency is used in many routes, the Session objects pile up because FastAPI only closes the generator when the request ends and the generator’s finally blo…
This walkthrough focuses on Gotcha: Unclosed Async Generators.
Before making a design choice, clarify:
- In a FastAPI app, it’s tempting to write a dependency that yields a DB session via an async generator: If the dependency is used in many routes, the Session objects pile up because FastAPI only closes the generator when…
- Forgetting that block means connections stay open, eventually exhausting the pool.
Concepts in play: python-concurrency-nogil, caching
Stage 1 — The Solution: asynccontextmanager + Depends
- Wrap the generator in asynccontextmanager from contextlib .
- FastAPI automatically calls the cleanup when the request finishes: FastAPI injects the yielded session and ensures the finally block runs even if the endpoint raises.
- This pattern scales: each request gets its own session, and resources are freed promptly.
from contextlib import asynccontextmanager
from fastapi import Depends, FastAPI
app = FastAPI()
@asynccontextmanager
async def get_session():
session = Session()
try:
yield session
finally:
await session.close() # guaranteed cleanup
@app.get("/items")
async def read_items(session: Session = Depends(get_session)):
return await session.execute("SELECT * FROM items")
Observable outcome: This pattern scales: each request gets its own session, and resources are freed promptly.
Stage 2 — Trade‑offs & Best Practices
- Quick checklist - Use asynccontextmanager for any async resource (DB, HTTP client, file).
- Explicitly await cleanup in the finally block.
- Avoid caching async generators unless you manage lifecycle yourself.
- Monitor connection pool metrics; a sudden spike indicates a leak.
Observable outcome: - Monitor connection pool metrics; a sudden spike indicates a leak.
End-to-end outcome
In a FastAPI app, it’s tempting to write a dependency that yields a DB session via an async generator: If the dependency is used in many routes, the Session objects pile up because FastAPI only closes the generator when the request ends and the generator’s finally block runs.
Alternatives considered
The source focuses on one primary design. A second architecture is not compared, so no alternative is invented here.
Failure and degraded modes
The source does not isolate a separate failure mode. Limits that matter for the scenario are called out in the stage decisions above.
Key learnings
- Wrap the generator in asynccontextmanager from contextlib .
- Quick checklist - Use asynccontextmanager for any async resource (DB, HTTP client, file).
