import asyncio from contextlib import asynccontextmanager from fastapi import FastAPI from config import USE_ASYNC_DOCKER, USE_DATABASE_STORAGE from session_manager import session_manager from http_pool import init_http_pool, shutdown_http_pool from database import init_database, shutdown_database, run_migrations from container_health import ( start_container_health_monitoring, stop_container_health_monitoring, ) from logging_config import get_logger, init_logging from routes import sessions_router, auth_router, health_router, proxy_router init_logging() logger = get_logger(__name__) _use_database_storage = USE_DATABASE_STORAGE @asynccontextmanager async def lifespan(app: FastAPI): global _use_database_storage logger.info("Starting Session Management Service") await init_http_pool() if _use_database_storage: try: await init_database() await run_migrations() await session_manager._load_sessions_from_database() logger.info("Database initialized and sessions loaded") except Exception as e: logger.error("Database initialization failed", extra={"error": str(e)}) if _use_database_storage: logger.warning("Falling back to JSON file storage") _use_database_storage = False session_manager._load_sessions_from_file() try: # Use the session manager's docker_service for health monitoring # This ensures the docker client stays alive for the lifetime of the application docker_client = session_manager.docker_service await start_container_health_monitoring(session_manager, docker_client) logger.info("Container health monitoring started") except Exception as e: logger.error( "Failed to start container health monitoring", extra={"error": str(e)} ) async def cleanup_task(): while True: await session_manager.cleanup_expired_sessions() await asyncio.sleep(300) cleanup_coro = asyncio.create_task(cleanup_task()) yield logger.info("Shutting down Session Management Service") cleanup_coro.cancel() await shutdown_http_pool() try: await stop_container_health_monitoring() logger.info("Container health monitoring stopped") except Exception as e: logger.error( "Error stopping container health monitoring", extra={"error": str(e)} ) if _use_database_storage: await shutdown_database() app = FastAPI( title="Lovdata Chat Session Manager", description="Manages isolated OpenCode containers for Norwegian legal research sessions", version="1.0.0", lifespan=lifespan, ) app.include_router(sessions_router) app.include_router(auth_router) app.include_router(health_router) app.include_router(proxy_router)