📦 EqualifyEverything / equalify-reflow

📄 health.py · 74 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74"""Health check endpoints."""

from typing import Any

from fastapi import APIRouter, Depends, HTTPException, status

from ..dependencies import get_queue_service, get_storage_service
from ..services import QueueService, StorageService

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


@router.get("")
async def health_check(
    storage: StorageService = Depends(get_storage_service),
    queue: QueueService = Depends(get_queue_service)
) -> dict[str, Any]:
    """
    Health check endpoint for container orchestration.

    Checks Redis, S3, and queue connectivity.

    Args:
        storage: Storage service (injected)
        queue: Queue service (injected)

    Returns:
        Health status with detailed checks
    """

    # Check docling-serve health
    try:
        from ..services.docling_serve_client import get_docling_client
        docling_client = get_docling_client()
        docling_healthy = await docling_client.check_health()
    except RuntimeError:
        docling_healthy = False

    checks = {
        "redis": await queue.check_redis_connection(),
        "s3": await storage.check_s3_access(),
        "queue_depth": await queue.check_queue_depth(),
        "docling_serve": docling_healthy,
    }

    # Core checks: Redis, S3, queue must pass
    # docling_serve is non-fatal — circuit breaker handles it at request level,
    # and it takes ~2min to load models at boot (would cause ECS restart loops)
    core_healthy = checks["redis"] and checks["s3"] and checks["queue_depth"] >= 0
    if core_healthy:
        return {
            "status": "healthy" if docling_healthy else "degraded",
            "checks": checks
        }
    else:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail={
                "status": "unhealthy",
                "checks": checks
            }
        )


@router.get("/ready")
async def readiness_check() -> dict[str, str]:
    """
    Readiness check for Kubernetes/orchestration.

    Returns:
        Ready status
    """
    return {"status": "ready"}