from django.conf import settings from django.db import connection, OperationalError from django.core.cache import cache from django.http import HttpResponse from rest_framework.decorators import api_view, permission_classes, authentication_classes from rest_framework.permissions import AllowAny from rest_framework.response import Response from rest_framework import status @api_view(["GET"]) @authentication_classes([]) @permission_classes([AllowAny]) def healthcheck(request): """Liveness + readiness probe endpoint. Returns 200 when all dependencies are reachable.""" checks = {} overall_ok = True # Database try: connection.ensure_connection() checks["db"] = "ok" except OperationalError as exc: checks["db"] = f"error: {exc}" overall_ok = False # Cache / Redis try: key = "_healthcheck" cache.set(key, "1", timeout=5) assert cache.get(key) == "1" checks["cache"] = "ok" except Exception as exc: checks["cache"] = f"error: {exc}" overall_ok = False http_status = status.HTTP_200_OK if overall_ok else status.HTTP_503_SERVICE_UNAVAILABLE return Response( {"status": "ok" if overall_ok else "degraded", "checks": checks}, status=http_status, ) @api_view(["GET"]) @authentication_classes([]) @permission_classes([AllowAny]) def metrics(request): """Prometheus metrics scrape endpoint. Restricted to internal networks via METRICS_ALLOWED_HOSTS setting (checked at the reverse-proxy level in prod). Returns 403 when the feature flag is off so the endpoint is a no-op in environments where it is not configured. """ if not getattr(settings, "METRICS_ENABLED", False): return HttpResponse(status=403) from prometheus_client import generate_latest, CONTENT_TYPE_LATEST return HttpResponse(generate_latest(), content_type=CONTENT_TYPE_LATEST)