""" Main FastAPI application entry point. Bootstraps the application with middleware, routers, and lifecycle handlers. """ from contextlib import asynccontextmanager from fastapi import APIRouter, FastAPI from fastapi.responses import ORJSONResponse from fastapi.middleware.cors import CORSMiddleware from core.config import settings from core.database import create_db_and_tables, close_database_connection from core.redis import init_redis, close_redis_connection from core.responses import ERROR_RESPONSES from observability.tracing import init_tracing, instrument_app, shutdown_tracing from observability.logging import setup_logging, get_logger from middleware.trace_context import TraceContextMiddleware from middleware.logging import RequestLoggingMiddleware from middleware.error_handler import register_exception_handlers # from apps.app_a.router import router as app_a_router # from apps.apple.router import router as app_b_router from apps.jd.router import router as jd_router logger = get_logger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): """ Application lifespan manager. Handles startup and shutdown events. """ # Startup logger.info("Starting application...") # Setup logging setup_logging() logger.info(f"Logging configured: level={settings.log_level}") # Initialize OpenTelemetry if settings.otel_enabled: init_tracing() instrument_app(app) logger.info( f"OpenTelemetry initialized: endpoint={settings.otel_exporter_endpoint}" ) # Initialize Redis await init_redis() logger.info(f"Redis initialized: {settings.redis_host}:{settings.redis_port}") # Create database tables (development only) if settings.is_development: await create_db_and_tables() logger.info("Database tables created") logger.info(f"Application started: environment={settings.environment}") yield # Shutdown logger.info("Shutting down application...") # Close Redis connection await close_redis_connection() logger.info("Redis connection closed") # Close database connection await close_database_connection() logger.info("Database connection closed") # Shutdown OpenTelemetry if settings.otel_enabled: await shutdown_tracing() logger.info("OpenTelemetry shutdown") logger.info("Application shutdown complete") # Create FastAPI application app = FastAPI( title=settings.app_name, description="A stateless, production-ready FastAPI web service platform", version="0.1.0", debug=settings.debug, lifespan=lifespan, docs_url="/docs", redoc_url="/redoc", openapi_url="/openapi.json", default_response_class=ORJSONResponse, # Use orjson for better performance ) # Add CORS middleware if settings.cors_enabled: app.add_middleware( CORSMiddleware, allow_origins=settings.cors_allow_origins, allow_credentials=settings.cors_allow_credentials, allow_methods=settings.cors_allow_methods, allow_headers=settings.cors_allow_headers, ) # Add custom middleware (order matters: last added = first executed) app.add_middleware(RequestLoggingMiddleware) app.add_middleware(TraceContextMiddleware) # Register exception handlers register_exception_handlers(app) router = APIRouter(prefix="/api") router.include_router(jd_router()) app.include_router(router) # Health check endpoint @app.get( "/health", tags=["Health"], summary="Health check", description="Check the health status of the application and its dependencies", responses={ 200: {"description": "Service is healthy"}, 500: ERROR_RESPONSES[500], 503: ERROR_RESPONSES[503], }, ) async def health_check(): """ Health check endpoint. Returns health status of the application and its components. """ from core.database import check_database_connection from core.redis import check_redis_connection # Check database db_healthy = await check_database_connection() # Check Redis redis_healthy = await check_redis_connection() # Overall health healthy = db_healthy and redis_healthy return { "status": "healthy" if healthy else "unhealthy", "components": { "api": "healthy", "database": "healthy" if db_healthy else "unhealthy", "redis": "healthy" if redis_healthy else "unhealthy", }, "environment": settings.environment, "version": "0.1.0", } # Root endpoint @app.get( "/", tags=["Root"], summary="Root endpoint", description="Get API information", responses={ 200: {"description": "API information retrieved successfully"}, }, ) async def root(): """Root endpoint with API information.""" return { "name": settings.app_name, "version": "0.1.0", "environment": settings.environment, "docs": "/docs", "health": "/health", } if __name__ == "__main__": import uvicorn uvicorn.run( "main:app", host=settings.host, port=settings.port, reload=settings.debug, log_level=settings.log_level.lower(), )