Skip to main content
Articles/async-context-manager/async-dependency-lifecycles-in-fastapi-when-generators-go-wrong
Scenario Article

Async Dependency Lifecycles in FastAPI: When Generators Go Wrong

Do you ever see “Connection pool exhausted” after a burst of requests?

Abstract Algorithms•Sep 15, 2026
Async Dependency Lifecycles in FastAPI: When Generators Go Wrong
💡 Executive Summary

⚠️ 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

  • ⚠️ 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 block runs.
  • Forgetting that block means connections stay open, eventually exhausting the pool.

Constraints & Assumptions

  • Operational latency, consistency levels, and network partition boundaries must be enforced.

⚡ Execution Stages & Decision Trace

1

Stage 1 — The Solution: `asynccontextmanager` + `Depends`

Action / Decision:

Wrap the generator in asynccontextmanager from contextlib .

Component Behavior:

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.

Observable Output: This pattern scales: each request gets its own session, and resources are freed promptly.
Read Full Stage in Deep Dive ↓
📖

Deep Dive

Detailed Architectural Analysis

Deep Dive: Stage 1 — The Solution: asynccontextmanager + Depends

Wrap the generator in asynccontextmanager from contextlib. FastAPI automatically calls the cleanup when the request finishes:

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")

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.

Observable outcome: This pattern scales: each request gets its own session, and resources are freed promptly.

Deep Dive: Stage 2 — Trade‑offs & Best Practices

AspectBenefitCaveat
Per‑request generatorIsolation, no shared stateSlight overhead of creating a session per call
asynccontextmanagerAutomatic cleanupMust await close; cannot reuse across requests
Dependency scopesDepends(get_session, use_cache=False)Forces new instance per request; default caching can be a source of leaks if misused

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.

By treating async generators as true context managers, you keep your FastAPI app lean, responsive, and free of resource leaks.

Observable outcome: By treating async generators as true context managers, you keep your FastAPI app lean, responsive, and free of resource leaks.

📊 System Outcome & Trade-offs

End-to-End Result: The system enforces causal consistency and bounded operations across distributed nodes.

Observed User & Operator Behavior

User: Clients observe deterministic state without lost updates or race conditions.

Operator: Operators can verify stage outcomes against the scenario requirements.

Key Architectural Trade-offs

  • System guarantees are traded against replication overhead and failover convergence times.
✅

Key learnings

  • Wrap the generator in asynccontextmanager from contextlib .
  • Quick checklist - Use asynccontextmanager for any async resource (DB, HTTP client, file).
NEXT LEARNING STEPApply & Defend Decisions

Apply Concepts from this Scenario

Test your understanding of the architecture decisions and trade-offs presented in this case study.

Share this case study

Discuss architecture trade-offs and lessons with your team.

Share:XLinkedInReddit