Files
FabledCurator/backend/app/extensions.py
T

53 lines
1.4 KiB
Python

"""Process-wide singleton async engine + session helper.
Previously every API blueprint lazily built its own engine via make_engine(),
so the process ran N connection pools. This module owns ONE engine for the
whole app; create_app() disposes it on shutdown via after_serving.
"""
from contextlib import asynccontextmanager
from sqlalchemy.ext.asyncio import (
AsyncEngine,
async_sessionmaker,
create_async_engine,
)
from .config import get_config
_engine: AsyncEngine | None = None
_sessionmaker: async_sessionmaker | None = None
def get_engine() -> AsyncEngine:
global _engine, _sessionmaker
if _engine is None:
_engine = create_async_engine(
get_config().database_url, pool_pre_ping=True, future=True
)
_sessionmaker = async_sessionmaker(_engine, expire_on_commit=False)
return _engine
def _get_sessionmaker() -> async_sessionmaker:
if _sessionmaker is None:
get_engine()
assert _sessionmaker is not None
return _sessionmaker
@asynccontextmanager
async def get_session():
"""`async with get_session() as session:` — one shared pool."""
Session = _get_sessionmaker()
async with Session() as session:
yield session
async def dispose_engine() -> None:
global _engine, _sessionmaker
if _engine is not None:
await _engine.dispose()
_engine = None
_sessionmaker = None