Files
LabGraph/backend/apps/health/views.py
T

75 lines
2.0 KiB
Python

"""
Health check endpoint required by the docker-compose web service healthcheck:
test: ["CMD-SHELL", "curl -fs http://localhost:8000/api/health/ || exit 1"]
Does NOT require authentication — the docker daemon calls this, not users.
Returns HTTP 200 when all services are healthy, HTTP 503 on any failure.
"""
import logging
from django.core.cache import cache
from django.db import OperationalError, connection
from django.http import JsonResponse
from django.views import View
logger = logging.getLogger(__name__)
VERSION = "1.0.0"
class HealthCheckView(View):
"""
Synchronous health check for web, database, and Redis.
Response body:
{
"status": "ok" | "degraded",
"version": "1.0.0",
"services": {
"database": "ok" | "error",
"redis": "ok" | "error"
}
}
"""
def get(self, request) -> JsonResponse: # type: ignore[override]
db_status = _check_database()
redis_status = _check_redis()
all_ok = db_status == "ok" and redis_status == "ok"
http_status = 200 if all_ok else 503
return JsonResponse(
{
"status": "ok" if all_ok else "degraded",
"version": VERSION,
"services": {
"database": db_status,
"redis": redis_status,
},
},
status=http_status,
)
def _check_database() -> str:
try:
with connection.cursor() as cursor:
cursor.execute("SELECT 1")
return "ok"
except OperationalError:
logger.exception("Database health check failed")
return "error"
def _check_redis() -> str:
try:
cache.set("_health_check", "1", timeout=5)
if cache.get("_health_check") != "1":
raise RuntimeError("Redis round-trip failed")
return "ok"
except Exception:
logger.exception("Redis health check failed")
return "error"