Hurricane Performance Benchmark Suite

To measure real-world concurrency, latency distributions, and container scaling characteristics under synthetic load, we created the Django Hurricane Benchmark Suite on GitHub.

The suite evaluates django-hurricane (targeting version 2.0.0rc1 and newer releases powered by Granian's Rust runtime) against PostgreSQL 17, upstream microservices, complex template rendering, and session authentication.


Architecture Overview

The benchmark infrastructure uses Docker Compose to orchestrate isolated container environments driven by headless Locust step-load testing:

Rendering diagram...

The 6 Evaluated Deployment Paradigms

The suite compares six distinct deployment paradigms across Hurricane's runtime engines:

  1. WSGI (Worker=1 / Single Thread): Hurricane WSGI mode with --workers 1 (strict single-threaded baseline for 1-to-1 comparison with single-process event loop).
  2. WSGI (Auto Threads / Multi-Thread): Hurricane WSGI mode with auto-threads calculation min(32, cpu_count + 4) threads (traditional production multi-threaded WSGI deployment).
  3. ASGI (Forced Sync Views): Hurricane ASGI mode running standard synchronous Django views, demonstrating the exact penalty of Django's sync_to_async(thread_sensitive=True) adapter under load.
  4. ASGI (Clean Async / Single Thread): Hurricane ASGI mode with clean async views (async def), pooled httpx async HTTP client, and --workers 1.
  5. ASGI (Auto Threads / Clean Async): Hurricane ASGI mode with clean async views and Hurricane's auto-threads calculation min(32, cpu_count + 4) threads for non-blocking threadpool dispatch and template rendering.
  6. ASGI + django-async-backend: Hurricane ASGI mode paired with django-async-backend utilizing true non-blocking psycopg 3 async connection pooling via Product.async_objects on the Tokio event loop.

Workload Routes

The test application exercises seven realistic traffic paths reflecting modern production architectures:

RouteFeature AreaConcurrency Characteristic
POST /api/auth/loginSession & Auth MiddlewareCookie signing, session read/write, user credentials validation.
GET /api/auth/meSession VerificationNative async session verification (auser under ASGI).
GET /catalog/renderComplex Template RenderingDjango Template Language (DTL) overhead, nested loops, filters, context processors.
GET /api/items & POST /api/itemsJSON API SerializationJSON parsing, model validation, and bulk ORM queries.
GET /external/fetchUnreliable Upstream APIInteracts with a mock upstream API (fake-api with randomized latency) simulating third-party network delays.
GET /catalog/searchDatabase Queries & AggregationsFiltering, foreign key joins (select_related), and statistical aggregations on PostgreSQL 17.
GET /api/gateway/aggregateScatter-Gather Microservices API GatewayFan-out to 3 microservices: sequential blocking in WSGI vs asyncio.gather() parallel sockets in ASGI.

Aggregate Performance Metrics (Mixed Workload)

The mixed workload simulates simultaneous user activity across all 7 routes with user concurrency ramping up to 100 concurrent users:

FlavorServer RuntimeThroughputMedian (p50)95th (p95)99th (p99)Error RateTotal Requests
WSGI (Worker=Auto / Multi-Thread)Hurricane WSGI147.3 req/s230.0 ms510.0 ms570.0 ms0.0%2,217
ASGI (Forced Sync Views)Hurricane ASGI71.5 req/s280.0 ms1900.0 ms2000.0 ms0.0%1,073
ASGI (Worker=Auto / Clean Async)Hurricane ASGI60.6 req/s300.0 ms2300.0 ms2600.0 ms0.0%910
ASGI (Worker=1 / Clean Async)Hurricane ASGI60.1 req/s350.0 ms2200.0 ms2500.0 ms0.0%901
ASGI + django-async-backendHurricane ASGI59.8 req/s720.0 ms1800.0 ms2700.0 ms0.0%898
WSGI (Worker=1 / Single Thread)Hurricane WSGI29.1 req/s1300.0 ms3000.0 ms3100.0 ms0.0%435
Throughput (Requests per Second - Higher is better)
WSGI (Worker=Auto / Multi-Thread) [████████████████████████████████]    147.3 req/s
ASGI (Forced Sync Views)         [████████████████                ]     71.5 req/s
ASGI (Worker=Auto / Clean Async) [█████████████                   ]     60.6 req/s
ASGI (Worker=1 / Clean Async)    [█████████████                   ]     60.1 req/s
ASGI + django-async-backend      [█████████████                   ]     59.8 req/s
WSGI (Worker=1 / Single Thread)  [██████                          ]     29.1 req/s
95th Percentile Latency (Lower is better)
WSGI (Worker=Auto / Multi-Thread) [█████                           ]    510.0 ms
ASGI + django-async-backend      [███████████████████             ]   1800.0 ms
ASGI (Forced Sync Views)         [████████████████████            ]   1900.0 ms
ASGI (Worker=1 / Clean Async)    [███████████████████████         ]   2200.0 ms
ASGI (Worker=Auto / Clean Async) [█████████████████████████       ]   2300.0 ms
WSGI (Worker=1 / Single Thread)  [████████████████████████████████]   3000.0 ms

Concurrency Scaling Penalty

As concurrent simulated users ramp up from light load (12 users) through mid load (50 users) to peak concurrency (100 users), response times scale differently across deployment flavors:

FlavorInitial Load (~12 Users) p50 / p95Mid Load (~50 Users) p50 / p95Peak Load (100 Users) p50 / p95Latency Scaling Penalty
WSGI (Worker=Auto / Multi-Thread)60.0 ms / 130.0 ms73.0 ms / 240.0 ms207.5 ms / 465.0 ms3.58x
WSGI (Worker=1 / Single Thread)240.0 ms / 510.0 ms880.0 ms / 1200.0 ms1250.0 ms / 2650.0 ms5.20x
ASGI (Forced Sync Views)110.0 ms / 240.0 ms180.0 ms / 420.0 ms267.5 ms / 1600.0 ms6.67x
ASGI (Worker=1 / Clean Async)99.0 ms / 260.0 ms240.0 ms / 530.0 ms330.0 ms / 1900.0 ms7.31x
ASGI + django-async-backend92.0 ms / 200.0 ms210.0 ms / 770.0 ms667.5 ms / 1575.0 ms7.88x
ASGI (Worker=Auto / Clean Async)120.0 ms / 230.0 ms230.0 ms / 510.0 ms290.0 ms / 1925.0 ms8.37x

Isolated Workload Performance

When endpoints are benchmarked in isolation without cross-traffic contention, the architectural strengths of each paradigm become distinct:

API Gateway / BFF (Scatter-Gather Fan-Out)

FlavorThroughputMedian (p50)95th (p95)Error Rate
WSGI (Worker=Auto / Multi-Thread)100.8 req/s410.0 ms840.0 ms0.0%
ASGI (Forced Sync Views)87.1 req/s390.0 ms1100.0 ms0.0%
ASGI (Worker=Auto / Clean Async)47.1 req/s770.0 ms2300.0 ms0.0%
ASGI (Worker=1 / Clean Async)46.7 req/s730.0 ms2600.0 ms0.0%
ASGI + django-async-backend39.4 req/s950.0 ms2900.0 ms0.0%
WSGI (Worker=1 / Single Thread)12.5 req/s2800.0 ms5600.0 ms0.0%

External Fetch (Upstream API I/O)

FlavorThroughputMedian (p50)95th (p95)Error Rate
WSGI (Worker=Auto / Multi-Thread)175.6 req/s150.0 ms360.0 ms0.0%
ASGI (Forced Sync Views)107.4 req/s330.0 ms830.0 ms0.0%
ASGI + django-async-backend74.6 req/s570.0 ms1500.0 ms0.0%
ASGI (Worker=1 / Clean Async)73.1 req/s500.0 ms1700.0 ms0.0%
ASGI (Worker=Auto / Clean Async)72.1 req/s480.0 ms1500.0 ms0.0%
WSGI (Worker=1 / Single Thread)22.9 req/s1600.0 ms3500.0 ms0.0%

Catalog Search (PostgreSQL Joins & Aggregates)

FlavorThroughputMedian (p50)95th (p95)Error Rate
WSGI (Worker=Auto / Multi-Thread)153.1 req/s200.0 ms500.0 ms0.0%
ASGI + django-async-backend90.2 req/s520.0 ms880.0 ms0.0%
WSGI (Worker=1 / Single Thread)89.0 req/s520.0 ms990.0 ms0.0%
ASGI (Forced Sync Views)73.7 req/s630.0 ms1300.0 ms0.0%
ASGI (Worker=Auto / Clean Async)70.0 req/s670.0 ms1400.0 ms0.0%
ASGI (Worker=1 / Clean Async)69.3 req/s650.0 ms1400.0 ms0.0%

Reproducing the Benchmarks Locally

Clone the repository and run the automated execution suite:

git clone https://github.com/django-hurricane/django-hurricane-bench.git
cd django-hurricane-bench

# Run full sequential benchmark across all 6 flavors:
./scripts/run_benchmark.sh

# Target a specific Hurricane version and concurrency parameters:
HURRICANE_VERSION=2.0.0rc6 BENCH_USERS=150 BENCH_DURATION=45s ./scripts/run_benchmark.sh

For continuous testing, the suite also runs in GitHub Actions via workflow_dispatch, automatically archiving reports under archive/ upon completion.