Framework Guide

Django API Monitoring

Set up health check endpoints and uptime monitoring for your Django application. Works with Django REST Framework and standard Django views.

Why Monitor Your Django App?

Django applications rely on multiple moving parts in production -- database connections, cache backends, Celery workers, and static file storage. Any of these can fail independently while the Django process itself keeps running. External monitoring catches these partial failures before users start seeing 500 errors.

  • Database connection drops -- PostgreSQL or MySQL connections can timeout or get reset, causing intermittent query failures
  • Migration drift -- A deployment that skips migrations leaves your schema out of sync, causing silent data corruption
  • Cache backend failures -- Redis or Memcached going down can cascade into slow queries and high database load
  • Celery worker stalls -- Background task workers can silently stop processing jobs, building up a growing queue

Simple Health View

# health/views.py
from django.http import JsonResponse
from datetime import datetime

def health(request):
    return JsonResponse({
        'status': 'healthy',
        'timestamp': datetime.utcnow().isoformat()
    })

# urls.py
from django.urls import path
from health import views

urlpatterns = [
    path('health/', views.health, name='health'),
]

Comprehensive Health Check

# health/views.py
from django.http import JsonResponse
from django.db import connection
from django.core.cache import cache
from django.conf import settings
from datetime import datetime
import time

def health(request):
    """Liveness probe - just confirms Django is running"""
    return JsonResponse({'status': 'healthy'})

def ready(request):
    """Readiness probe - checks all dependencies"""
    checks = {}
    healthy = True

    # Check database
    try:
        start = time.time()
        with connection.cursor() as cursor:
            cursor.execute('SELECT 1')
            cursor.fetchone()
        checks['database'] = {
            'status': 'ok',
            'response_time_ms': round((time.time() - start) * 1000, 2)
        }
    except Exception as e:
        healthy = False
        checks['database'] = {'status': 'error', 'message': str(e)}

    # Check cache (Redis/Memcached)
    try:
        start = time.time()
        cache.set('health_check', 'ok', 10)
        cache.get('health_check')
        checks['cache'] = {
            'status': 'ok',
            'response_time_ms': round((time.time() - start) * 1000, 2)
        }
    except Exception as e:
        healthy = False
        checks['cache'] = {'status': 'error', 'message': str(e)}

    response = {
        'status': 'healthy' if healthy else 'unhealthy',
        'timestamp': datetime.utcnow().isoformat(),
        'checks': checks,
        'version': getattr(settings, 'VERSION', 'unknown')
    }

    status_code = 200 if healthy else 503
    return JsonResponse(response, status=status_code)

Using django-health-check

For a more robust solution, use the django-health-check package:

# Install
pip install django-health-check

# settings.py
INSTALLED_APPS = [
    # ...
    'health_check',
    'health_check.db',
    'health_check.cache',
    'health_check.storage',
    'health_check.contrib.migrations',
    'health_check.contrib.celery',  # if using Celery
    'health_check.contrib.redis',   # if using Redis
]

# urls.py
urlpatterns = [
    path('health/', include('health_check.urls')),
]

Django REST Framework

# health/views.py
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework import status
from django.db import connection

@api_view(['GET'])
@permission_classes([AllowAny])
def health(request):
    return Response({'status': 'healthy'})

@api_view(['GET'])
@permission_classes([AllowAny])
def ready(request):
    try:
        with connection.cursor() as cursor:
            cursor.execute('SELECT 1')
        return Response({
            'status': 'healthy',
            'checks': {'database': 'ok'}
        })
    except Exception as e:
        return Response({
            'status': 'unhealthy',
            'checks': {'database': str(e)}
        }, status=status.HTTP_503_SERVICE_UNAVAILABLE)

Exclude from Middleware

Skip authentication and logging for health checks:

# middleware.py
class HealthCheckMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.path in ['/health/', '/ready/']:
            # Skip other middleware for health checks
            from health.views import health
            return health(request)
        return self.get_response(request)

Best Practices

  • Separate liveness and readiness — /health for "is Django running", /ready for "are dependencies working"
  • Skip authentication — Monitoring services need unauthenticated access
  • Check migrations — Ensure database schema is up to date
  • Add timeouts — Don't let slow checks hang forever

Common Django Production Issues

Database Connection Pooling

Django creates a new database connection per request by default. Under high traffic, this can exhaust your database's connection limit. Use CONN_MAX_AGE in your settings or a connection pooler like PgBouncer. Include a database ping in your readiness check to detect connection issues early.

Slow Migrations on Deploy

Running migrate on large tables can lock them for minutes, causing timeouts. External monitoring detects when your app becomes unresponsive during migration-heavy deployments. Use django-health-check with migration checks to verify schema state.

Static File Serving Failures

When using S3, GCS, or other storage backends for static/media files, network issues can make your entire site look broken. Include a storage check in your health endpoint to catch cloud storage outages before users report broken images.

CSRF and Session Backend Failures

If your session backend (Redis, database) goes down, all authenticated requests fail with 403 errors. Your health check should verify the cache/session backend is reachable. Make sure health endpoints themselves skip CSRF and session middleware.

Frequently Asked Questions

How do I add a health check to Django without a third-party package?
Create a simple view that returns a JsonResponse with status 200. Add it to your urls.py at /health/. Use django.db.connection to verify database connectivity and django.core.cache to check your cache backend. Return 503 if any dependency is unreachable.
Should I use django-health-check or write my own?
For simple apps, a custom view is sufficient and has zero dependencies. Use django-health-check when you need built-in checks for databases, caches, storage backends, Celery, and migrations. It also provides a standard HTML dashboard and JSON API out of the box.
How do I skip Django middleware for health check requests?
Create a custom middleware class that intercepts requests to /health/ early in the middleware chain, before authentication or CSRF middleware runs. Place it first in your MIDDLEWARE setting. This ensures health checks respond quickly without loading sessions or checking tokens.
How do I monitor Django Celery workers?
Include a Celery check in your health endpoint by inspecting the broker connection and checking queue sizes. Use django-health-check's Celery plugin, or manually ping the broker with app.control.ping(). Monitor both the web process and worker processes separately with UptimeSignal.
How often should I monitor my Django application?
For production Django apps, check every 1-5 minutes. UptimeSignal's free tier checks every 5 minutes, which catches most outages within minutes. Pro tier supports 1-minute intervals for mission-critical applications. Ensure your health endpoint responds in under 500ms to avoid false positives.

Monitor your Django API

Add your health endpoint to UptimeSignal and get alerted when it fails. Free tier includes 25 monitors.

Start monitoring free →

No credit card required. Commercial use allowed.

More Framework Guides