Bring some chaos to your Django app!

Did you ever need a simple machinery that would break your website randomly?
Who would want to do that on purpose, you think, right? Well, I would...

There is one project powered by Django Rest Framework that I take care of. The purpose of it is really simple - to provide a stable, real-life API for teaching purposes for other people to play with it.

One day we thought - what kind of a real-life API it is if it doesn't crash?! And how closer to a real API it would be if it would slow the connection from time to time or crash in a completely random manner!

There are already tools providing similar purpose, The Netflix's Chaos Monkey being one of them, but it's like using a sledgehammer to crack a nut - we have a single API server and a database, nothing more. We also don't want to make sure the API will always stay operable but we want to make it down on purpose. Although for a short time and not too often.

This is how the ChaosMiddleware has been created. Let's not waste the time, here's the PoC written in like 20 minutes, still doing its job.

import random
from time import sleep

from django.http import HttpResponse


DELAY_PROBABILITY = 10
DELAY_RANGE = list(range(1, 4)) # simplest random value to not overengineer the code
ERROR_PROBABILITY = 20
ERRORS = [
(404, 'Resource not found'),
(418, "I'm a teapot"),
(500, "Server error"),
(400, "Bad request"),
(408, 'Request Timeout'),
(429, 'Too Many Requests'),
]


class ChaosMiddleware:
def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):

if not request.path.startswith('/admin'): # leave admin pages fully operable
should_delay = random.randint(1, ELAY_PROBABILITY) == 1
should_crash = random.randint(1, ERROR_PROBABILITY) == 1

if should_delay:
delay_value = random.choice(DELAY_RANGE)
sleep(delay_value)

if should_crash:
error_status, error_reason = random.choice(ERRORS)
return HttpResponse(status=error_status, content=error_reason, reason=error_reason)

response = self.get_response(request)

return response

Including the above middleware, the application will randolmy crash or delay few requests with the probability estimated to respectively 1 per 20 requests for crash or 1 per 10 requests for the delay, giving random errors.

The last thing is to include our ChaosMiddleware to your MIDDLEWARES inside the settings.py file and the code will do the rest.

Now it's time watch the world burns... 👹