from collections.abc import AsyncIterator, Callable from contextlib import AbstractAsyncContextManager, asynccontextmanager import structlog from fastapi import FastAPI from src.bootstrap.dependencies import AppResources from src.config import Settings from src.infrastructure.minio.client import create_client as create_minio_client from src.infrastructure.observability.logging import configure_logging from src.infrastructure.postgres.database import create_engine, create_sessionmaker from src.infrastructure.qdrant.client import create_client as create_qdrant_client logger = structlog.get_logger(__name__) def create_lifespan( settings: Settings | None = None, ) -> Callable[[FastAPI], AbstractAsyncContextManager[None, bool | None]]: @asynccontextmanager async def lifespan(app: FastAPI) -> AsyncIterator[None]: resolved_settings = settings or Settings() configure_logging(resolved_settings.logging) db_engine = create_engine(resolved_settings.postgres) db_sessionmaker = create_sessionmaker(db_engine) logger.info("lifespan.postgres.engine.created") minio_client = create_minio_client(resolved_settings.minio) logger.info("lifespan.minio.client.created") qdrant_client = create_qdrant_client(resolved_settings.qdrant) logger.info("lifespan.qdrant.client.created") app.state.resources = AppResources( settings=resolved_settings, db_engine=db_engine, db_sessionmaker=db_sessionmaker, minio_client=minio_client, qdrant_client=qdrant_client, ) try: yield finally: try: await db_engine.dispose() except Exception: logger.exception("lifespan.postgres.dispose.failed") try: await qdrant_client.close() except Exception: logger.exception("lifespan.qdrant.close.failed") return lifespan