from collections.abc import AsyncGenerator from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine from app.core.app_settings import settings # Explizite Pool-Grenzen (postgres-expert-Review-Fund): ohne das erzeugt jeder # uvicorn-Worker einen eigenen Default-Pool (5 + 10 Overflow), was bei mehreren # Workern auf dem 4GB-VPS PostgreSQL max_connections (per Tuning-Config auf 50 # begrenzt, siehe deploy/install_server.sh) sprengen kann. pool_recycle gegen # von der DB nach Idle-Timeout gekappte Verbindungen. engine = create_async_engine( settings.database_url, pool_pre_ping=True, pool_size=5, max_overflow=5, pool_recycle=1800, ) SessionLocal = async_sessionmaker(engine, expire_on_commit=False) async def get_db() -> AsyncGenerator[AsyncSession, None]: """Konvention für alle Endpunkte: Erfolg -> commit, Exception -> rollback. Endpunkte selbst rufen kein `db.commit()`/`db.rollback()` auf, sondern verlassen sich auf diese Dependency (Review-Fund: Konvention muss zentral, nicht pro Endpunkt copy-paste sein). """ async with SessionLocal() as session: try: yield session await session.commit() except Exception: await session.rollback() raise