from __future__ import annotations from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.api.router import api_router from app.core.config import get_settings from app.core.database import create_tables from app.core.exception_handlers import register_exception_handlers from app.core.observability import RequestObservabilityMiddleware, configure_logging from app.services.secret_service import SecretService from app.services.maintenance_service import MaintenanceService from app.services.periodic_report_worker import PeriodicReportWorker import asyncio @asynccontextmanager async def lifespan(app: FastAPI): settings = get_settings() SecretService.validate_production_key() if settings.auto_create_tables: create_tables() maintenance_task = asyncio.create_task(MaintenanceService.run_forever()) periodic_report_task = asyncio.create_task(PeriodicReportWorker.run_forever()) try: yield finally: for task in (maintenance_task, periodic_report_task): task.cancel() for task in (maintenance_task, periodic_report_task): try: await task except asyncio.CancelledError: pass settings = get_settings() configure_logging(settings.log_level) app = FastAPI(title=settings.app_name, version="0.1.0", lifespan=lifespan) register_exception_handlers(app) app.add_middleware(RequestObservabilityMiddleware) app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.include_router(api_router, prefix=settings.api_prefix) @app.get("/") def root() -> dict[str, str]: return {"name": settings.app_name, "status": "ok"}