"""Health check endpoints — liveness, readiness, and full health. /health/live — process is alive (always 200 if running) /health/ready — ready to serve requests (checks DB, Redis, storage) /api/v1/health — full health with all checks (backward compatible) """ from __future__ import annotations from fastapi import APIRouter from pydantic import BaseModel from app.core.monitoring import get_health_status from app.schemas.common import HealthResponse router = APIRouter(tags=["health"]) class LiveResponse(BaseModel): status: str = "alive" class ReadyResponse(BaseModel): status: str # "ready" or "not_ready" checks: dict[str, str] = {} @router.get("/health/live") async def health_live() -> LiveResponse: """Liveness probe — process is alive. Returns 200 if the process is running. Used by Kubernetes/Coolify for restart decisions. """ return LiveResponse(status="alive") @router.get("/health/ready") async def health_ready() -> ReadyResponse: """Readiness probe — ready to serve requests. Checks: - PostgreSQL connection - Redis connection - Storage backend - Worker heartbeat (if available) Returns 200 if all checks pass, 503 if any fail. Used by load balancer to route traffic. """ health = await get_health_status() checks = {} all_ready = True # health is a dict (or HealthResponse), handle both health_checks = health.get('checks', {}) if isinstance(health, dict) else (health.checks or {}) for check_name, check_val in health_checks.items(): # Handle both string status and dict with status key if isinstance(check_val, dict): status_val = check_val.get("status", "unknown") else: status_val = str(check_val) status = "ok" if status_val in ("ok", "up", "healthy", "true", "True") else "fail" checks[check_name] = status if status != "ok": all_ready = False return ReadyResponse( status="ready" if all_ready else "not_ready", checks=checks, ) @router.get("/api/v1/health", response_model=HealthResponse) async def health(): """Full health check — no auth required. Returns status (healthy/degraded) and individual checks for database, redis, storage, and worker. """ return await get_health_status()