import os from modules.logger_tool import initialise_logger logger = initialise_logger(__name__, os.getenv("LOG_LEVEL"), os.getenv("LOG_PATH"), 'default', True) from fastapi import FastAPI, HTTPException import uvicorn import requests from typing import Dict, Any from modules.database.tools.neo4j_driver_tools import get_driver from run.initialization.initialization import InitializationSystem import time import ssl from run.setup import setup_cors from run.routers import register_routes from run.initialization import initialize_system # FastAPI App Setup app = FastAPI() setup_cors(app) # Health check endpoint @app.get("/health") async def health_check() -> Dict[str, Any]: """Health check endpoint that verifies all service dependencies""" health_status = { "status": "healthy", "services": { "neo4j": {"status": "healthy", "message": "Connected"}, "supabase": {"status": "healthy", "message": "Connected"} } } try: # Check Neo4j driver = get_driver() if not driver: health_status["services"]["neo4j"] = { "status": "unhealthy", "message": "Failed to connect to Neo4j" } health_status["status"] = "unhealthy" except Exception as e: health_status["services"]["neo4j"] = { "status": "unhealthy", "message": f"Error checking Neo4j: {str(e)}" } health_status["status"] = "unhealthy" try: # Minimal check to confirm Supabase is responsive (e.g., pinging auth or storage endpoint) supabase_url = os.getenv("SUPABASE_URL") service_role_key = os.getenv("SERVICE_ROLE_KEY") response = requests.get( f"{supabase_url}/auth/v1/health", headers={"apikey": service_role_key}, timeout=5 ) if response.status_code != 200: health_status["services"]["supabase"] = { "status": "unhealthy", "message": f"Supabase Auth API returned status {response.status_code}" } health_status["status"] = "unhealthy" except Exception as e: health_status["services"]["supabase"] = { "status": "unhealthy", "message": f"Error checking Supabase Auth API: {str(e)}" } health_status["status"] = "unhealthy" if health_status["status"] == "unhealthy": raise HTTPException(status_code=503, detail=health_status) return health_status # Register routes register_routes(app) # Initialize system with retry logic def initialize_with_retry(max_attempts: int = 3, initial_delay: int = 5) -> bool: """Initialize the system with retry logic""" attempt = 0 delay = initial_delay while attempt < max_attempts: try: logger.info(f"Attempting system initialization (attempt {attempt + 1}/{max_attempts})") initialize_system() logger.info("System initialization completed successfully") return True except Exception as e: attempt += 1 if attempt == max_attempts: logger.error(f"System initialization failed after {max_attempts} attempts: {str(e)}") return False logger.warning(f"Initialization attempt {attempt} failed: {str(e)}. Retrying in {delay} seconds...") time.sleep(delay) delay *= 2 # Exponential backoff return False if __name__ == "__main__": import uvicorn import os # Run initialization with retry logic if not initialize_with_retry(): logger.error("Failed to initialize system after multiple attempts") # Continue anyway to allow the API to start and handle health checks if os.getenv('BACKEND_DEV_MODE') == 'true': logger.info("Running with Reload") uvicorn.run( "main:app", host="0.0.0.0", port=int(os.getenv('PORT_BACKEND', 8000)), log_level="info", proxy_headers=True, timeout_keep_alive=10, reload=True ) else: logger.info("Running without Reload and without SSL (behind reverse proxy)") uvicorn.run( "main:app", host="0.0.0.0", port=int(os.getenv('PORT_BACKEND', 8000)), # <-- not 443 log_level="info", proxy_headers=True, timeout_keep_alive=10, workers=int(os.getenv('UVICORN_WORKERS', '1')) )