Django Health Check — Complete Implementation Guide
In this tutorial, you will learn about Django Health Check. We cover key concepts, practical examples, and best practices to help you master this topic.
Django health checks verify database connectivity, cache availability, and application functionality, integrating with django-health-check library and Kubernetes probes through dedicated endpoints.
What You'll Learn
By the end of this tutorial, you will know how to add health checks to Django using the django-health-check library, create custom health checks, configure URLs for Kubernetes probes, and handle dependency failures.
Why It Matters
Django powers many production web applications. Proper health checks ensure Django services work correctly with Kubernetes, load balancers, and monitoring systems.
Real-World Use
DodaTech's Django-based content management system uses django-health-check with custom checks for the database, Redis cache, Elasticsearch, and CDN connectivity.
Django Health Check Learning Path
flowchart LR
A[Express Health Check] --> B[Django Health Check]
B --> C[django-health-check]
B --> D[Custom Checks]
B --> E[Kubernetes Probes]
B --> F{You Are Here}
style F fill:#f90,color:#fff
Installing and Configuring django-health-check
The django-health-check library provides built-in checks for common Django components.
# requirements.txt
django-health-check>=3.16.0
# settings.py
INSTALLED_APPS = [
# ...
"health_check",
"health_check.db",
"health_check.cache",
"health_check.storage",
"health_check.contrib.migrations",
]
# urls.py
from django.urls import path, include
urlpatterns = [
path("ht/", include("health_check.urls")),
# ...
]
# GET /ht/ -> 200 {"status": "healthy", "checks": [...]}
# GET /ht/ -> 503 {"status": "unhealthy", "checks": [...]}
Running Built-in Health Checks
The library provides several built-in checks out of the box.
# health_check.db checks database connectivity
# health_check.cache checks cache backend
# health_check.storage checks file storage
# To run checks manually:
from health_check.views import MainView
# The main view returns:
# - HTTP 200 if all checks pass
# - HTTP 503 if any check fails
# - JSON or HTML response based on Accept header
# Example response when healthy:
# {
# "status": "healthy",
# "checks": [
# {"identifier": "DatabaseBackend", "status": "working", "time_taken": 0.01},
# {"identifier": "CacheBackend", "status": "working", "time_taken": 0.005}
# ]
# }
# Example response when database is down:
# {
# "status": "unhealthy",
# "checks": [
# {"identifier": "DatabaseBackend", "status": "error",
# "message": "cannot connect to database", "time_taken": 5.0}
# ]
# }
Custom Health Check
Create custom health checks for application-specific components.
# checks.py
from health_check.backends import BaseHealthCheckBackend
from health_check.exceptions import HealthCheckException
import requests
from django.conf import settings
class ExternalAPICheck(BaseHealthCheckBackend):
critical_service = True
def check_status(self):
try:
response = requests.get(
settings.EXTERNAL_API_HEALTH_URL,
timeout=5
)
if response.status_code != 200:
raise HealthCheckException(
f"External API returned {response.status_code}"
)
except requests.ConnectionError:
raise HealthCheckException("Cannot connect to external API")
except requests.Timeout:
raise HealthCheckException("External API health check timed out")
def identifier(self):
return "external-api"
class RedisQueueCheck(BaseHealthCheckBackend):
critical_service = False # Non-critical dependency
def check_status(self):
from django.core.cache import cache
test_key = "health:test"
cache.set(test_key, "ok", 5)
value = cache.get(test_key)
if value != "ok":
raise HealthCheckException("Cache read/write test failed")
cache.delete(test_key)
def identifier(self):
return "redis-queue"
# settings.py
HEALTH_CHECK_BACKENDS = [
"health_check.db.backends.DatabaseBackend",
"health_check.cache.backends.CacheBackend",
"myapp.checks.ExternalAPICheck",
"myapp.checks.RedisQueueCheck",
]
Health Check URLs for Kubernetes Probes
Configure Django URLs for Kubernetes probe endpoints.
# urls.py
from django.urls import path
from django.http import JsonResponse
from health_check.views import MainView
def liveness_probe(request):
"""Returns 200 if the process is alive."""
return JsonResponse({"status": "alive"})
def readiness_probe(request):
"""Returns 200 only if all critical dependencies are healthy."""
view = MainView.as_view()
response = view(request)
return response
def startup_probe(request):
"""Returns 200 after initialization completes."""
from django.db import connections
try:
connections["default"].ensure_connection()
return JsonResponse({"status": "started"})
except Exception:
return JsonResponse({"status": "starting"}, status=503)
urlpatterns = [
path("healthz/", liveness_probe, name="liveness"),
path("readyz/", readiness_probe, name="readiness"),
path("startupz/", startup_probe, name="startup"),
]
Graceful Shutdown Integration
Handle Django's shutdown signal to mark the service as unhealthy.
# apps.py
from django.apps import AppConfig
import atexit
class HealthAppConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "myapp"
def ready(self):
self.shutting_down = False
@atexit.register
def mark_shutting_down():
self.shutting_down = True
# middleware.py
import threading
class ShutdownMiddleware:
shutting_down = threading.Event()
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.path in ["/healthz/", "/readyz/", "/startupz/"]:
if self.shutting_down.is_set():
from django.http import JsonResponse
return JsonResponse(
{"status": "shutting_down"},
status=503
)
return self.get_response(request)
Common Mistakes
Not registering custom health checks -- Custom checks must be listed in HEALTH_CHECK_BACKENDS settings. The library only discovers built-in checks automatically.
Making health checks too expensive -- Django health checks run on every probe. Keep them lightweight. A database SELECT 1 is fine; a full ORM query over thousands of records is not.
Not distinguishing critical and non-critical dependencies -- Set critical_service=False for non-critical dependencies. A Redis cache failure shouldn't make the entire service unhealthy.
Forgetting to configure database connections -- The database health check requires a working DATABASES configuration. If the database is intentionally offline, remove the DB check.
Not handling Migration checks in production -- The migrations check verifies all migrations are applied. In production during a deployment, this can cause false failures if migrations run after the new code starts.
Practice Questions
What library provides built-in health checks for Django? django-health-check. It includes checks for database, cache, storage, and migrations.
How do you create a custom health check in Django? Subclass BaseHealthCheckBackend, implement check_status() and identifier(), then add the class to HEALTH_CHECK_BACKENDS.
What is the difference between critical_service=True and False? True means the check failure makes the service unhealthy (HTTP 503). False means the failure is reported but doesn't affect overall status.
Challenge: Implement a Django health check that verifies a third-party API is accessible and returns correct data.
class ThirdPartyAPICheck(BaseHealthCheckBackend):
critical_service = True
def check_status(self):
import requests
try:
response = requests.get(
"https://api.example.com/health",
headers={"Authorization": f"Bearer {settings.API_TOKEN}"},
timeout=3
)
if response.status_code != 200:
raise HealthCheckException(f"API returned {response.status_code}")
data = response.json()
if data.get("status") != "ok":
raise HealthCheckException("API reports unhealthy")
except requests.exceptions.RequestException as e:
raise HealthCheckException(str(e))
def identifier(self):
return "third-party-api"
FAQ
Mini Project
Build a Django health check configuration with custom checks for database, cache, external API, and queue, with separate endpoints for Kubernetes liveness, readiness, and startup probes.
# Complete health configuration
import django
from django.conf import settings
settings.configure(
DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
INSTALLED_APPS=["health_check", "health_check.db", "health_check.cache"],
HEALTH_CHECK_BACKENDS=["health_check.db.backends.DatabaseBackend"],
)
django.setup()
# Run health check
from health_check.backends import BaseHealthCheckBackend
from health_check.exceptions import ServiceUnavailable
class CustomHealthCheck(BaseHealthCheckBackend):
def check_status(self):
if not self.check_condition():
raise ServiceUnavailable("Service unavailable")
def check_condition(self):
return True
def identifier(self):
return "custom-check"
What's Next
Now that you understand Django health checks, learn about Go health check implementation. Then explore Spring Boot Actuator health endpoints.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro