102 lines
3.4 KiB
Python
102 lines
3.4 KiB
Python
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"]) |