import asyncio import logging import asyncpg from sqlalchemy import text from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine from sqlalchemy.orm import sessionmaker from api.config import settings from api.models.base import Base import api.models.video # noqa: F401 - register model with Base.metadata logger = logging.getLogger("db") engine = create_async_engine(settings.database_url, echo=False, future=True) SessionLocal = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) async def wait_for_postgres(retries: int = 30, delay: float = 1.0) -> None: """Wait for the postgres server to accept connections (using the default 'postgres' db).""" last_exc: Exception | None = None for attempt in range(1, retries + 1): try: conn = await asyncpg.connect( user=settings.DB_USER, password=settings.DB_PASS, database="postgres", host=settings.DB_HOST, port=int(settings.DB_PORT), ) await conn.close() return except Exception as e: last_exc = e wait = min(delay * (2 ** (attempt - 1)), 5) logger.info("Waiting for postgres (attempt %s/%s): %s", attempt, retries, e) await asyncio.sleep(wait) raise RuntimeError(f"Could not connect to postgres after {retries} attempts") from last_exc async def _create_database_if_missing() -> None: admin = await asyncpg.connect( user=settings.DB_USER, password=settings.DB_PASS, database="postgres", host=settings.DB_HOST, port=int(settings.DB_PORT), ) try: exists = await admin.fetchval( "SELECT 1 FROM pg_database WHERE datname=$1", settings.DB_NAME ) if not exists: await admin.execute(f'CREATE DATABASE "{settings.DB_NAME}"') finally: await admin.close() async def init_db() -> None: await _create_database_if_missing() async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all)