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