A Modern Django Health Check for AWS ELB

Published

Years ago I wrote an article about how to handle AWS ELB's health check in Django. I pulled that article a few years ago because I felt it was out of date, yet the URL still gets visited every day. Here is an updated approach to how to handle a health check for Django. (And it should work on any platform.)

Not long after I implemented this approach for Prideraiser, I stumbled on django-health-check by the fine folx at RevSys. It's a great package and I highly recommend it if you need more than a basic check or want a pluggable system to write your own checks. But for Prideraiser I try to use as few dependencies as possible and keep things simple.

The Approach #

The approach is simple. A custom middleware that intercepts a request with the URL "/health-check/" and returns a 200 response. That's it. The problem we're trying to overcome is that ELB's health check doesn't set a host header, which causes Django to raise a 400 error because of the ALLOWED_HOSTS setting. By using a middleware and putting it earlier in the stack than Django's security middleware, we return a response before Django gets a chance to raise an error.

The Code #

import typing

from django import http
from django.conf import settings


class HealthCheckMiddleware:
    def __init__(
        self, get_response: typing.Callable[[http.HttpRequest], http.HttpResponse]
    ):
        self.get_response = get_response

    def __call__(self, request: http.HttpRequest):
        if request.path == getattr(settings, "HEALTH_CHECK_URL", "/health-check/"):
            output = {
                "status": "🏳️‍🌈🖤🤎🏳️‍⚧️⚽️",
                "timestamp": datetime.datetime.now().isoformat(),
            }
            return http.JsonResponse(output)
        return self.get_response(request)

This is as basic as I could make it. There's only one setting, HEALTH_CHECK_URL, that lets us override what URL to listen to. The response is a JSON response with a timestamp and a status message. The status message can be anything you want. We went with our emoji stack for some fun.

Here's what our MIDDLEWARE setting looks like:

MIDDLEWARE = [
    "prideraiser.middleware.health_check.HealthCheckMiddleware",
    "django.middleware.security.SecurityMiddleware",
    # other middleware
]

That's all there is to it. Now you've got a simple way to return a health check in Django no matter what the host.