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"}