한양과학기술고등학교

에듀테크 프로젝트 대시보드

Lifespan 이벤트

lifespan asynccontextmanager startup shutdown app.state

앱 시작 시 커넥션 풀·ML 모델·HTTP 클라이언트를 만들고, 종료 시 정리합니다.

1. lifespan 컨텍스트 매니저

from contextlib import asynccontextmanager
from fastapi import FastAPI

@asynccontextmanager
async def lifespan(app: FastAPI):
    # ── startup ──
    app.state.http = httpx.AsyncClient()
    app.state.db_pool = await create_pool(settings.database_url)
    yield
    # ── shutdown ──
    await app.state.http.aclose()
    await app.state.db_pool.close()

app = FastAPI(lifespan=lifespan)

2. app.state 사용

from fastapi import Request

@app.get("/proxy")
async def proxy(request: Request):
    r = await request.app.state.http.get("https://api.example.com")
    return r.json()

3. 의존성으로 노출하기 (권장)

def get_http(request: Request) -> httpx.AsyncClient:
    return request.app.state.http

HttpDep = Annotated[httpx.AsyncClient, Depends(get_http)]

@app.get("/proxy")
async def proxy(http: HttpDep):
    r = await http.get("https://api.example.com")
    return r.json()

4. 구식 @app.on_event

# deprecated — 새 코드는 lifespan 사용
@app.on_event("startup")
async def startup(): ...

@app.on_event("shutdown")
async def shutdown(): ...

5. Gunicorn 다중 워커 주의

이 서버 환경
  • Gunicorn 워커마다 lifespan 이 각각 실행됨 → 워커 수 만큼 풀·클라이언트가 생김
  • DB pool_size 설정 시 워커수 × pool_size 가 실제 커넥션 상한 — PostgreSQL max_connections 와 비교
"API 스키마는 코드가 곧 문서다 (/docs)"