"""Operational endpoints used by Docker/Kubernetes probes and by humans.""" from __future__ import annotations from typing import Any from django.conf import settings from django.db import connection from drf_spectacular.utils import extend_schema from rest_framework import status from rest_framework.permissions import AllowAny from rest_framework.request import Request from rest_framework.response import Response from rest_framework.views import APIView from apps.search.backends import get_search_backend class LivenessView(APIView): """Cheap check: the process is up and can answer HTTP.""" permission_classes = [AllowAny] authentication_classes: list = [] throttle_classes: list = [] @extend_schema(tags=["health"], responses={200: dict}) def get(self, request: Request) -> Response: # noqa: ARG002 return Response({"status": "ok", "service": settings.SERVICE_NAME}) class ReadinessView(APIView): """ Deep check: verifies every dependency the API needs to serve traffic. Returns 503 when any dependency is down so an orchestrator stops routing traffic to this instance. """ permission_classes = [AllowAny] authentication_classes: list = [] throttle_classes: list = [] @extend_schema(tags=["health"], responses={200: dict, 503: dict}) def get(self, request: Request) -> Response: # noqa: ARG002 checks: dict[str, Any] = { "database": _check(_database), "search": _check(_search), } healthy = all(c["healthy"] for c in checks.values()) return Response( {"status": "ok" if healthy else "degraded", "checks": checks}, status=status.HTTP_200_OK if healthy else status.HTTP_503_SERVICE_UNAVAILABLE, ) def _check(fn) -> dict[str, Any]: # noqa: ANN001 try: detail = fn() except Exception as exc: # noqa: BLE001 - health checks must never raise return {"healthy": False, "detail": str(exc)[:200]} return {"healthy": True, "detail": detail} def _database() -> str: with connection.cursor() as cursor: cursor.execute("SELECT 1") cursor.fetchone() return "reachable" def _search() -> str: backend = get_search_backend() backend.ping() return f"{backend.name} reachable"