Django health check configuration and patterns using django-health-check for system monitoring, Docker healthchecks, and Kubernetes probes. Trigger: When implementing health checks, monitoring endpoints, or readiness/liveness probes in Django.
Install
npx skillscat add carlos-asg/tu-voz-en-ruta/django-health Install via the SkillsCat registry.
SKILL.md
What is django-health-check?
django-health-check is a pluggable app that provides health check endpoints for Django applications. It's essential for:
- Container orchestration: Docker Compose, Kubernetes liveness/readiness probes
- Load balancers: Health-based routing decisions
- Monitoring systems: Uptime tracking, alerting
- Multi-tenant apps: Database and migrations status per tenant
Key Benefits:
- Built-in checks: database, cache, storage, migrations
- Custom check support
- JSON/HTML output formats
- Pluggable architecture
- Works in public schema (no tenant required)
Installation
pip install django-health-check# settings.py
INSTALLED_APPS = [
# ...
"health_check",
"health_check.db", # Database connectivity
"health_check.contrib.migrations", # Pending migrations check
# Optional checks:
# "health_check.cache", # Cache backend
# "health_check.storage", # File storage
# "health_check.contrib.celery", # Celery workers
# "health_check.contrib.redis", # Redis
]URL Configuration (REQUIRED)
Important: Health checks should be accessible in the public schema (without tenant) for Docker/Kubernetes to reach them easily.
# urls_public.py (Public URLs - no tenant required)
from django.urls import path, include
urlpatterns = [
path("health/", include("health_check.urls")),
# Other public URLs...
]# settings.py
PUBLIC_SCHEMA_URLCONF = "buzon_quejas.urls_public" # Health checks here
ROOT_URLCONF = "buzon_quejas.urls_tenant" # Tenant-specific URLsAvailable Endpoints
# Check all health endpoints
curl http://localhost:8000/health/
# Get JSON response
curl http://localhost:8000/health/?format=json
# Check specific component
curl http://localhost:8000/health/db/
curl http://localhost:8000/health/migrations/
curl http://localhost:8000/health/cache/Response Example (JSON):
{
"db": "working",
"migrations": "working"
}HTTP Status Codes:
200 OK: All checks passed500 Internal Server Error: One or more checks failed
Built-in Checks
Database Check
# Enabled by: "health_check.db" in INSTALLED_APPS
# Checks: Can connect to database and execute queries
# URL: /health/db/Migrations Check
# Enabled by: "health_check.contrib.migrations" in INSTALLED_APPS
# Checks: No pending migrations
# URL: /health/migrations/Cache Check
# Enabled by: "health_check.cache" in INSTALLED_APPS
# Checks: Can read/write to cache backend
# URL: /health/cache/Docker Healthcheck (REQUIRED)
# Dockerfile
FROM python:3.11-slim
# ... other setup ...
# Health check for Docker
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD curl -f http://localhost:8000/health/ || exit 1# docker-compose.yml
services:
web:
build: .
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health/"]
interval: 30s
timeout: 3s
retries: 3
start_period: 40sKubernetes Probes (REQUIRED)
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: django-app
spec:
template:
spec:
containers:
- name: web
image: myapp:latest
# Liveness probe: Restart if unhealthy
livenessProbe:
httpGet:
path: /health/
port: 8000
httpHeaders:
- name: Host
value: localhost
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
# Readiness probe: Remove from service if not ready
readinessProbe:
httpGet:
path: /health/
port: 8000
httpHeaders:
- name: Host
value: localhost
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3Probe Differences:
| Probe | Purpose | Failure Action |
|---|---|---|
| Liveness | Is app alive? | Restart container |
| Readiness | Is app ready? | Remove from service (no traffic) |
| Startup | Has app started? | Wait before other probes |
Custom Health Checks
# myapp/health_checks.py
from health_check.backends import BaseHealthCheckBackend
from health_check.exceptions import ServiceUnavailable
class TenantCountCheck(BaseHealthCheckBackend):
"""Check if at least one tenant exists."""
critical_service = False # True = fail entire health check if this fails
def check_status(self):
from apps.organization.models import Organization
try:
tenant_count = Organization.objects.count()
if tenant_count == 0:
self.add_error(ServiceUnavailable("No tenants configured"))
except Exception as e:
self.add_error(ServiceUnavailable(f"Error checking tenants: {e}"))
def identifier(self):
return "tenant_count"
# Register custom check
# settings.py
INSTALLED_APPS = [
# ...
"myapp", # Contains health_checks.py
]
# myapp/apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = "myapp"
def ready(self):
from health_check.plugins import plugin_dir
from .health_checks import TenantCountCheck
plugin_dir.register(TenantCountCheck)Multi-tenant Considerations
For django-tenants apps:
✅ DO:
- Configure health checks in public schema (
PUBLIC_SCHEMA_URLCONF) - Use database checks to verify PostgreSQL connectivity
- Use migrations check to verify schema sync
❌ DON'T:
- Put health checks behind tenant middleware (Docker/K8s can't provide tenant domain)
- Check tenant-specific data in health checks (use separate monitoring for that)
Monitoring Integration
Uptime Monitoring (UptimeRobot, Pingdom, etc.)
Monitor URL: https://tuvozenruta.com/health/
Check interval: 1-5 minutes
Expected status: 200 OK
Alert on: 500 errors or timeoutPrometheus + Grafana
# For Prometheus metrics, use django-prometheus instead:
# pip install django-prometheus
# settings.py
INSTALLED_APPS = [
"django_prometheus",
# ...
]
MIDDLEWARE = [
"django_prometheus.middleware.PrometheusBeforeMiddleware",
# ... other middleware ...
"django_prometheus.middleware.PrometheusAfterMiddleware",
]
# urls_public.py
urlpatterns = [
path("metrics/", include("django_prometheus.urls")),
path("health/", include("health_check.urls")),
]Common Commands
# Test health endpoint locally
curl http://localhost:8000/health/
# Test with JSON format
curl http://localhost:8000/health/?format=json
# Test specific check
curl http://localhost:8000/health/db/
# Test from Docker container
docker compose exec web curl -f http://localhost:8000/health/
# View health check in browser (HTML output)
open http://localhost:8000/health/Best Practices Checklist
ALWAYS:
- ✅ Configure health checks in public schema (no tenant required)
- ✅ Use database check to verify PostgreSQL connectivity
- ✅ Use migrations check to catch schema drift
- ✅ Add Docker HEALTHCHECK in Dockerfile
- ✅ Configure Kubernetes liveness + readiness probes
- ✅ Set reasonable timeouts (3s is good default)
- ✅ Test health endpoints work without authentication
- ✅ Return JSON format for programmatic checks
- ✅ Use
critical_service=Falsefor non-essential custom checks - ✅ Monitor health endpoint with external service
NEVER:
- ❌ Put health checks behind tenant middleware
- ❌ Require authentication for health endpoints
- ❌ Make health checks do expensive operations
- ❌ Use same probe settings for liveness and readiness
- ❌ Set initialDelaySeconds too low (app needs time to start)
- ❌ Forget to install
curlin Docker image for healthcheck
Troubleshooting
Health check returns 500
# Check logs for specific error
docker compose logs web | grep health
# Test each check individually
curl http://localhost:8000/health/db/
curl http://localhost:8000/health/migrations/Docker healthcheck failing
# Check if curl is installed in container
docker compose exec web which curl
# Check if port 8000 is listening
docker compose exec web netstat -tlnp | grep 8000
# Manually run healthcheck command
docker compose exec web curl -f http://localhost:8000/health/Kubernetes probe failing
# Check pod logs
kubectl logs <pod-name>
# Check probe configuration
kubectl describe pod <pod-name>
# Manually test from pod
kubectl exec -it <pod-name> -- curl http://localhost:8000/health/Resources
- Documentation: https://github.com/revsys/django-health-check
- Docker healthcheck: https://docs.docker.com/engine/reference/builder/#healthcheck
- Kubernetes probes: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/