from fastapi import FastAPI, Request, status from fastapi.responses import JSONResponse from fastapi.concurrency import asynccontextmanager import logging from app.infrastructure.scheduler import process_pending_calls from app.api.uis import router as uis_router from app.core.exceptions import CallEventAlreadyExistsError, DatabaseError, ValidationError from apscheduler.schedulers.asyncio import AsyncIOScheduler from fastapi import FastAPI import asyncio from app.infrastructure.database import get_db # Настройка логирования logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(app:FastAPI): scheduler = AsyncIOScheduler() scheduler.add_job(process_pending_calls, "interval", seconds = 10) scheduler.start() yield await scheduler.shutdown(wait=True) app = FastAPI( title="Ingest Service API", description="Микросервис для приема событий звонков", version="1.0.0", lifespan=lifespan ) # Exception handlers @app.exception_handler(CallEventAlreadyExistsError) async def call_event_exists_handler(request: Request, exc: CallEventAlreadyExistsError): """Обработчик для дубликатов событий звонков""" logger.warning(f"Duplicate call event: {exc.message}", extra=exc.details) return JSONResponse( status_code=status.HTTP_409_CONFLICT, content={ "error": "duplicate_call_event", "message": exc.message, "details": exc.details } ) @app.exception_handler(DatabaseError) async def database_error_handler(request: Request, exc: DatabaseError): """Обработчик для ошибок БД""" logger.error(f"Database error: {exc.message}", extra=exc.details) return JSONResponse( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={ "error": "database_error", "message": "Internal database error occurred", "details": exc.details } ) @app.exception_handler(ValidationError) async def validation_error_handler(request: Request, exc: ValidationError): """Обработчик для ошибок валидации""" logger.warning(f"Validation error: {exc.message}", extra=exc.details) return JSONResponse( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, content={ "error": "validation_error", "message": exc.message, "details": exc.details } ) @app.exception_handler(Exception) async def general_exception_handler(request: Request, exc: Exception): """Общий обработчик для неперехваченных исключений""" logger.error(f"Unhandled exception: {str(exc)}", exc_info=True) return JSONResponse( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={ "error": "internal_server_error", "message": "An unexpected error occurred" } ) # Health check endpoint @app.get("/health", tags=["Health"]) async def health_check(): """Проверка состояния сервиса""" return {"status": "healthy", "service": "ingest-service"} app.include_router(uis_router, prefix="/v1/uis", tags=["UIS Webhooks"])