Source code for api_gateway.routers.health

"""
Health Check Router
Monitors service availability and system health
"""

from datetime import datetime, timezone
from typing import Optional

import httpx
from api_gateway.service_metrics import refresh_backend_health
from fastapi import APIRouter, HTTPException, Request

router = APIRouter(prefix="", tags=["health"])


def _get_runtime_config(request: Request) -> tuple[str, Optional[str], Optional[str], bool, float]:
    rag_service_url = getattr(request.app.state, "rag_service_url", None)
    if not rag_service_url:
        raise HTTPException(status_code=500, detail="RAG service URL not configured")
    embedding_service_url = getattr(request.app.state, "embedding_service_url", None)
    rerank_service_url = getattr(request.app.state, "rerank_service_url", None)
    rerank_enabled = bool(getattr(request.app.state, "rerank_enabled", False))
    timeout = getattr(request.app.state, "healthcheck_timeout_seconds", 5.0)
    return rag_service_url, embedding_service_url, rerank_service_url, rerank_enabled, float(timeout)


[docs] @router.get("/health") async def health_check(request: Request) -> dict[str, object]: """ health check for API Gateway and dependent services. Returns: - 200 if all services are healthy - 503 if any critical service is down """ is_healthy = True services_status: dict[str, str] = {} rag_service_url, embedding_service_url, rerank_service_url, rerank_enabled, timeout = _get_runtime_config(request) # Check all critical services services_to_check: dict[str, str] = {"rag_service": rag_service_url} if rerank_enabled and rerank_service_url: services_to_check["rerank_service"] = rerank_service_url # Optional services (checked but don't affect overall health) optional_services: dict[str, str] = {} if embedding_service_url: optional_services["embedding_service"] = embedding_service_url if rerank_service_url and not rerank_enabled: optional_services["rerank_service"] = rerank_service_url for service_name, service_url in services_to_check.items(): try: async with httpx.AsyncClient(timeout=timeout) as client: response = await client.get(f"{service_url}/health") services_status[service_name] = "healthy" if response.status_code == 200 else "unhealthy" if response.status_code != 200: is_healthy = False except Exception: services_status[service_name] = "unreachable" is_healthy = False # Check optional services (don't affect overall health) for service_name, service_url in optional_services.items(): try: async with httpx.AsyncClient(timeout=timeout) as client: response = await client.get(f"{service_url}/health") status = "healthy (optional)" if response.status_code == 200 else "unhealthy (optional)" services_status[service_name] = status except Exception: services_status[service_name] = "unreachable (optional)" response_payload: dict[str, object] = { "status": "healthy" if is_healthy else "unhealthy", "timestamp": datetime.now(timezone.utc).isoformat(), "services": services_status, } await refresh_backend_health(request.app) if not is_healthy: raise HTTPException(status_code=503, detail=response_payload) return response_payload