[{"data":1,"prerenderedAt":277},["ShallowReactive",2],{"search-api":3},[4,17,29,39,51,64,75,90,101,119,132,143,154,164,173,182,193,203,217,229,241,255,268],{"id":5,"path":6,"dir":7,"title":8,"description":7,"keywords":9,"body":16},"content:0.index.md","\u002F","","Django Hurricane - The Django-Native Application Server",[10,11,12,13,14,15],"Latest Release","Built for Production Excellence","The Django-Native Advantage","Proven Track Record","Quickstart","Community & Support","    🚀   Version 2.0.0rc6 is live!    Explore the release & PyPI package ↓   The Django-Native Application Server   High-performance, battle-tested, and built specifically for Django. Zero-config WSGI & ASGI, built-in edge defense, native static serving, and deep health observability—ready for Docker, Kubernetes, and Cloud.  Latest Release    Built for Production Excellence    Fast HTTP parsing powered by Hyper & Tokio. Delivers zero-copy networking, async socket dispatch, and 2x higher throughput than Gunicorn or Tornado.   Native Rust file streaming with kernel sendfile and HTTP 304 caching. Includes zero-setup dynamic finders fallback for development and automated collectstatic workflows.   Instantly drops automated scanners (probing for   .php ,   \u002F.env ,   \u002Fwp-admin\u002F ) at the gateway in \u003C0.35 microseconds. Shields Django middleware, sessions, and database connection pools.   Gateway rate limiting with client IP resolution via   X-Forwarded-For  for load balancers and Ingress. Silently drops volumetric floods with zero log spam.   Built-in   \u002Falive ,   \u002Fready ,   \u002Fstartup , and   \u002Fmetrics  endpoints. Compatible out-of-the-box with AWS ALBs, Docker healthchecks, Prometheus, and Kubernetes probes.   Run any project with   python manage.py serve . Seamlessly auto-detects   WSGI_APPLICATION  or   ASGI_APPLICATION  from your settings with zero extra config files.   The Django-Native Advantage  Django was developed with a batteries-included philosophy and gracefully handles complex web application challenges. But in production—whether running on a single Docker container, an AWS\u002FFly.io PaaS, or an autoscaling Kubernetes cluster—Django needs more than generic server wrappers like Gunicorn.  It's Not Just About Running a Container  Generic servers like Gunicorn, Uvicorn, and Nginx know nothing about Django settings, URL patterns, or database lifecycles. Hurricane brings   Django-native intelligence  to the application server layer:    Zero-Nginx Architecture:  Serve static and media files natively with kernel sendfile speed, or develop with live dynamic finders without running   collectstatic .   Edge Attack Immunity:  Automated bot vulnerability scans (  wp-login.php ,   .env ) are dropped at Tier 2 without ever touching Django middlewares or database connections.   Migration & Health Synchronization:  Preflight database migrations (  --check-migrations-apply ) prevent traffic routing until the database is ready.   Traffic Shedding & Deadlock Detection:  Real queue depth metrics signal load balancers and orchestrators when worker queues saturate, diverting traffic before requests time out.  Hurricane solves these architectural friction points directly at the server layer, giving your Django applications the reliability and resilience required in modern cloud platforms.   Proven Track Record  Developed and maintained by    Blueshoe  and open-source contributors:    Battle-tested in Production:  Running critical Django workloads across enterprise Kubernetes clusters since 2020.   Thorough Test Coverage:  Comprehensive test suite with automated Kubernetes end-to-end (k3d) validation and cross-process telemetry tests.   Independently Benchmarked:  2x throughput increase and 100% elimination of false probe flaps verified in the    django-hurricane-bench  suite.   Cloud-Native Standards:  Fully compliant with CNCF standards, OpenMetrics, and 12-factor application guidelines.   Quickstart  1. Install Hurricane     uv   add   django-hurricane\n     pip   install   django-hurricane\n  2. Add to   INSTALLED_APPS     INSTALLED_APPS   =   [\n       # Standard Django apps...\n       \"django.contrib.admin\"  ,\n       \"django.contrib.auth\"  ,\n       # ...\n       # Add Hurricane:\n       \"hurricane\"  ,\n   ]\n  3. Launch Your Server     python   manage.py   serve\n     2026-10-21 12:00:00 INFO hurricane.server.general Django Hurricane web server active.\n   2026-10-21 12:00:00 INFO hurricane.server.fast_404 Fast-404 active in prefix mode (9 prefixes, 31 signatures)\n   2026-10-21 12:00:00 INFO hurricane.server.limiter Rate limiter active: 10.0 req\u002Fs (burst: 30) [IP Header: X-Forwarded-For]\n   2026-10-21 12:00:00 INFO hurricane.server.general Starting probe application running on port 8001 (\u002Fstartup, \u002Falive, \u002Fready, \u002Fmetrics)\n   2026-10-21 12:00:00 INFO hurricane.server.general Starting HTTP Server on port 8000\n   2026-10-21 12:00:00 INFO hurricane.server.general Startup time is 0.114 seconds\n   Read the Getting Started Guide   Explore the Product Roadmap →   Community & Support  Have questions, architectural ideas, or need help optimizing your deployment? Join the community:   Chat with the team on    Discord  Follow and connect on    LinkedIn  Star the project and contribute on    GitHub  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":18,"path":19,"dir":20,"title":21,"description":22,"keywords":23,"body":28},"content:1.guides:1.getting-started.md","\u002Fguides\u002Fgetting-started","guides","Getting Started","How to install and configure Django Hurricane in your Django project.",[24,25,26,27],"1. Installation","2. Configure Django settings.py","3. Launching the Server","4. Verifying Endpoints","  Getting Started  Getting started with Django Hurricane takes less than two minutes.   1. Installation  Install Hurricane using    Astral uv  (recommended) or standard   pip :     uv   add   django-hurricane\n     pip   install   django-hurricane\n   2. Configure Django   settings.py  Add   \"hurricane\"  to your   INSTALLED_APPS :     INSTALLED_APPS   =   [\n       # Standard Django apps...\n       \"django.contrib.admin\"  ,\n       \"django.contrib.auth\"  ,\n       \"django.contrib.contenttypes\"  ,\n       \"django.contrib.sessions\"  ,\n       \"django.contrib.messages\"  ,\n       \"django.contrib.staticfiles\"  ,\n       # Add Hurricane:\n       \"hurricane\"  ,\n   ]\n   3. Launching the Server  Run the   serve  management command:     python   manage.py   serve\n  Hurricane will initialize:     2026-10-21 12:00:00 INFO hurricane.server.general Granian-powered Django web server. Version: 2.0.0rc6\n   2026-10-21 12:00:00 INFO hurricane.server.fast_404 Fast-404 active in prefix mode (9 prefixes, 31 signatures)\n   2026-10-21 12:00:00 INFO hurricane.server.limiter Rate limiter active: 10.0 req\u002Fs (burst: 30) [IP Header: X-Forwarded-For]\n   2026-10-21 12:00:00 INFO hurricane.server.general Starting probe application running on port 8001 with route liveness-probe: \u002Falive, readiness-probe: \u002Fready, startup-probe: \u002Fstartup\n   2026-10-21 12:00:00 INFO hurricane.server.general Starting Prometheus metrics exporter on port 8001 with route \u002Fmetrics\n   2026-10-21 12:00:00 INFO hurricane.server.general Starting HTTP Server on port 8000\n   2026-10-21 12:00:00 INFO hurricane.server.general Startup time is 0.114 seconds\n   4. Verifying Endpoints  Open a new terminal window to test your endpoints:  Application Traffic (Port 8000):     curl   http:\u002F\u002Flocalhost:8000\u002F\n   # Returns your Django application's root view\n  Kubernetes Health Probes (Port 8001):     curl   http:\u002F\u002Flocalhost:8001\u002Falive\n   # Returns: alive (HTTP 200 OK)\n   \n   curl   http:\u002F\u002Flocalhost:8001\u002Fready\n   # Returns: OK (HTTP 200 OK)\n   \n   curl   http:\u002F\u002Flocalhost:8001\u002Fstartup\n   # Returns: Startup was finished ... (HTTP 200 OK)\n  Prometheus Metrics (Port 8001):     curl   http:\u002F\u002Flocalhost:8001\u002Fmetrics\n   # Returns Prometheus metric exposition:\n   # request_counter 1.0\n   # response_time_average 2.15\n   # request_queue_length 0\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":30,"path":31,"dir":20,"title":32,"description":33,"keywords":34,"body":38},"content:1.guides:2.developer-guide.md","\u002Fguides\u002Fdeveloper-guide","Developer Guide","Advanced development with custom health checks via the Django System Check Framework, custom Prometheus metrics, and remote debugging.",[35,36,37],"Custom Health Checks via Django System Check Framework","Custom Prometheus Metrics","Remote Debugging in Kubernetes","  Developer Guide  Extend Hurricane with custom application health checks, business observability metrics, and remote debugging tools.   Custom Health Checks via Django System Check Framework  Django includes a battle-tested    System Check Framework  designed to inspect your codebase, database schema, environment variables, and third-party integrations for operational anomalies.  Hurricane natively harnesses this framework for Kubernetes container lifecycles:    Readiness Probes (  tags=[\"readiness\"] ) : Executed on every   GET \u002Fready  probe. If any check tagged with   \"readiness\"  returns a Django   Error  or   Critical , Hurricane catches the exception, updates the Prometheus readiness metric to   0 , and responds with   HTTP 500 . Kubernetes immediately sheds Ingress traffic from the pod until the check passes.   Liveness Probes (  tags=[\"liveness\"] ) : Executed on every   GET \u002Falive  probe. If an unrecoverable failure occurs, returning an   Error  causes   \u002Falive  to fail. Repeated failures trigger Kubernetes to terminate and restart the pod (self-healing).   Startup Probes (  tags=[\"startup\"] ) : Executed during initial boot before traffic begins, ensuring critical migrations, encryption keys, and seed data are ready.   Practical Health Check Examples  Register custom checks in any installed app (typically inside a   checks.py  file imported in your   AppConfig.ready() ):  1. Database Integrity & Seed Data Check (  readiness )  Ensure critical database records exist (e.g. default tenant, active billing currencies, or configuration seed data) and that the database connection pool is healthy:     from   django.core.checks   import   Error,   Warning  , register\n   from   django.db   import   connection\n   \n   \n   @register  (  \"readiness\"  )\n   def   check_database_and_seed_data  (app_configs,   **  kwargs):\n       errors   =   []\n       try  :\n           with   connection.cursor()   as   cursor:\n               cursor.execute(  \"SELECT 1;\"  )\n               row   =   cursor.fetchone()\n               if   not   row   or   row[  0  ]   !=   1  :\n                   errors.append(\n                       Error(\n                           \"Database ping returned unexpected response.\"  ,\n                           hint  =  \"Check database connectivity and connection pool health.\"  ,\n                           id  =  \"myapp.E001\"  ,\n                       )\n                   )\n   \n           # Verify critical seed data or configuration records\n           from   myapp.models   import   SystemConfiguration\n   \n           if   not   SystemConfiguration.objects.filter(  is_active  =  True  ).exists():\n               errors.append(\n                   Error(\n                       \"Active SystemConfiguration record missing in database.\"  ,\n                       hint  =  \"Run database seed fixtures before launching traffic.\"  ,\n                       id  =  \"myapp.E002\"  ,\n                   )\n               )\n       except   Exception   as   exc:\n           errors.append(\n               Error(\n                   f  \"Database query failed during readiness check:   {  exc  }  \"  ,\n                   hint  =  \"Verify database network access, credentials, and pool limits.\"  ,\n                   id  =  \"myapp.E003\"  ,\n               )\n           )\n       return   errors\n   2. In-Cluster & Upstream Microservice Checks (  readiness )  Verify that upstream dependencies within your Kubernetes cluster (e.g. auth services, payment gateways, search clusters) are responding with acceptable latency:     import   urllib.request\n   from   django.core.checks   import   Error,   Warning  , register\n   \n   \n   @register  (  \"readiness\"  )\n   def   check_auth_microservice  (app_configs,   **  kwargs):\n       errors   =   []\n       # Upstream service running inside the Kubernetes cluster\n       auth_service_url   =   \"http:\u002F\u002Fauth-service.default.svc.cluster.local:8080\u002Fhealthz\"\n   \n       try  :\n           req   =   urllib.request.Request(auth_service_url,   headers  =  {  \"User-Agent\"  :   \"Hurricane-HealthCheck\"  })\n           with   urllib.request.urlopen(req,   timeout  =  1.5  )   as   resp:\n               if   resp.status   !=   200  :\n                   errors.append(\n                       Error(\n                           f  \"Auth microservice returned non-200 status:   {  resp.status  }  \"  ,\n                           hint  =  \"Check auth-service pod logs and Ingress routing.\"  ,\n                           id  =  \"myapp.E010\"  ,\n                       )\n                   )\n       except   Exception   as   exc:\n           # Returning Error sheds traffic until the upstream service is reachable\n           errors.append(\n               Error(\n                   f  \"Unable to reach upstream Auth service:   {  exc  }  \"  ,\n                   hint  =  \"Verify CoreDNS resolution and auth-service deployment health.\"  ,\n                   id  =  \"myapp.E011\"  ,\n               )\n           )\n       return   errors\n   3. Clock Synchronization & Solar \u002F Ephemeris State (  readiness )  Accurate system clocks are critical for JWT token validation, OAuth flows, and cryptographic signatures. Furthermore, time-sensitive applications (such as solar energy management, dynamic electricity tariffs, agricultural automation, or circadian lighting systems) depend on accurate astronomical calculations and timezone state:     import   time\n   from   datetime   import   datetime, timezone\n   from   django.core.checks   import   Error,   Warning  , register\n   \n   \n   @register  (  \"readiness\"  )\n   def   check_clock_and_solar_state  (app_configs,   **  kwargs):\n       errors   =   []\n   \n       # 1. System Clock Drift & Monotonicity Check\n       # Verify that local container time hasn't drifted wildly from UTC reference\n       now_utc   =   datetime.now(timezone.utc)\n       if   now_utc.year   \u003C   2026  :\n           errors.append(\n               Error(\n                   f  \"Container system clock is invalid:   {  now_utc.isoformat()  }  \"  ,\n                   hint  =  \"Verify host node chrony\u002FNTP synchronization in the Kubernetes cluster.\"  ,\n                   id  =  \"myapp.E020\"  ,\n               )\n           )\n   \n       # 2. Solar \u002F Astronomical Window Validation\n       # In smart energy or IoT deployments, ensure astronomical calculations are operational\n       try  :\n           from   myapp.services.astronomy   import   get_solar_elevation, is_daylight_tariff_active\n   \n           # Ensure solar coordinates computation returns valid physical range (-90 to +90 degrees)\n           solar_elevation   =   get_solar_elevation(  timestamp  =  now_utc)\n           if   not   (  -  90.0   \u003C=   solar_elevation   \u003C=   90.0  ):\n               errors.append(\n                   Error(\n                       f  \"Computed solar elevation out of bounds:   {  solar_elevation  }  \"  ,\n                       hint  =  \"Check ephemeris ephem\u002Fastral library installation and lat\u002Flong coordinates.\"  ,\n                       id  =  \"myapp.E021\"  ,\n                   )\n               )\n       except   ImportError  :\n           # Module not installed; skip solar check\n           pass\n       except   Exception   as   exc:\n           errors.append(\n               Warning  (\n                   f  \"Solar state computation error:   {  exc  }  \"  ,\n                   hint  =  \"Verify astronomical coordinates in settings.\"  ,\n                   id  =  \"myapp.W022\"  ,\n               )\n           )\n   \n       return   errors\n   4. Cache & Task Broker Liveness (  liveness )  Liveness probes should only fail on   unrecoverable process deadlocks  (where restarting the container fixes the issue):     from   django.core.checks   import   Error, register\n   import   redis\n   \n   \n   @register  (  \"liveness\"  )\n   def   check_local_worker_deadlock  (app_configs,   **  kwargs):\n       errors   =   []\n       # Verify that internal Python worker thread queues and event loop state are responsive\n       try  :\n           from   myapp.worker   import   get_worker_heartbeat\n   \n           last_heartbeat_seconds   =   get_worker_heartbeat()\n           if   last_heartbeat_seconds   >   60  :\n               errors.append(\n                   Error(\n                       f  \"Internal worker heartbeat frozen for   {  last_heartbeat_seconds  }  s.\"  ,\n                       hint  =  \"Worker thread is deadlocked; container restart required.\"  ,\n                       id  =  \"myapp.E030\"  ,\n                   )\n               )\n       except   Exception   as   exc:\n           errors.append(\n               Error(\n                   f  \"Worker thread health check failed:   {  exc  }  \"  ,\n                   id  =  \"myapp.E031\"  ,\n               )\n           )\n       return   errors\n   5. Storage Mounts & ML Model Artifacts (  startup )  Before marking a pod ready for traffic on boot, confirm that mounted persistent volumes (PVCs) contain required model weights or configuration files:     import   os\n   from   django.core.checks   import   Error, register\n   \n   \n   @register  (  \"startup\"  )\n   def   check_mounted_model_artifacts  (app_configs,   **  kwargs):\n       errors   =   []\n       model_path   =   \"\u002Fmodels\u002Fclassifier_v2.onnx\"\n   \n       if   not   os.path.exists(model_path):\n           errors.append(\n               Error(\n                   f  \"Required machine learning model artifact not found at '  {  model_path  }  '.\"  ,\n                   hint  =  \"Verify that the Kubernetes PersistentVolumeClaim (PVC) is correctly mounted.\"  ,\n                   id  =  \"myapp.E040\"  ,\n               )\n           )\n       elif   os.path.getsize(model_path)   \u003C   1024  :\n           errors.append(\n               Error(\n                   f  \"Model artifact file at '  {  model_path  }  ' appears corrupt or empty.\"  ,\n                   hint  =  \"Check initContainer model downloader logs.\"  ,\n                   id  =  \"myapp.E041\"  ,\n               )\n           )\n       return   errors\n   Best Practices for System Checks in Kubernetes    Keep Checks Fast & Non-Blocking : Readiness checks run periodically (typically every 2–5 seconds). Use strict network socket timeouts (e.g.   timeout=1.0 s) on all external HTTP or database calls.   Differentiate Severity :\n    Error  or   Critical : Triggers HTTP 500 on the probe, withdrawing or restarting the pod.   Warning  or   Info : Logged for observability without failing the health check.   Use the Right Tag :\n    readiness : Temporary external conditions (database high load, upstream API maintenance). Sheds traffic without killing the pod.   liveness : Unrecoverable internal conditions (deadlocked threads, corrupted memory heap). Kills and restarts the pod.   startup : One-time initialization prerequisites (schema migrations, seed data, model file downloads). Protects against premature liveness kills during cold starts.  For more details on registering and structuring checks, visit the    Official Django System Check Framework Documentation .   Custom Prometheus Metrics  You can register custom application metrics that are exposed directly on   \u002Fmetrics :     from   hurricane.metrics   import   CalculatedMetric, CounterMetric\n   from   myapp.models   import   Order\n   \n   \n   class   ActiveOrdersMetric  (  CalculatedMetric  ):\n       \"\"\"Current number of active processing orders.\"\"\"\n   \n       code   =   \"active_orders_count\"\n   \n       @  classmethod\n       def   get_value  (cls,   *  args):\n           return   Order.objects.filter(  status  =  \"processing\"  ).count()\n   \n   \n   class   UserSignupCounter  (  CounterMetric  ):\n       \"\"\"Total user registrations.\"\"\"\n   \n       code   =   \"user_signups_total\"\n  Increment counter in your views:     UserSignupCounter.increment()\n   Remote Debugging in Kubernetes  Debugging containerized Django applications in a remote Kubernetes cluster is easy with Hurricane's built-in DAP debugger support:  VS Code (Debugpy)  Start Hurricane with the   --debugger  flag:     python   manage.py   serve   --debugger   --debugger-port=5678\n  Add a configuration to   .vscode\u002Flaunch.json :     {\n     \"name\"  :   \"Attach: Remote Hurricane\"  ,\n     \"type\"  :   \"debugpy\"  ,\n     \"request\"  :   \"attach\"  ,\n     \"connect\"  : {\n       \"host\"  :   \"localhost\"  ,\n       \"port\"  :   5678\n     },\n     \"pathMappings\"  : [\n       {\n         \"localRoot\"  :   \"${workspaceFolder}\"  ,\n         \"remoteRoot\"  :   \"\u002Fapp\"\n       }\n     ]\n   }\n  Port-forward the debugger port (  kubectl port-forward pod\u002Fmy-pod 5678:5678 ) and press F5 in VS Code!  JetBrains PyCharm  Start Hurricane pointing to your PyCharm debug server:     python   manage.py   serve   --pycharm-host=host.docker.internal   --pycharm-port=8071\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":40,"path":41,"dir":20,"title":42,"description":43,"keywords":44,"body":50},"content:1.guides:3.kubernetes-deployment.md","\u002Fguides\u002Fkubernetes-deployment","Django on Kubernetes: The Complete Production Guide","Production-ready architectural guide for running Django on Kubernetes. Covers pod lifecycles, health probes, database migrations, zero-downtime rolling updates, and HPA autoscaling.",[45,46,47,48,49],"Production Deployment Manifest","Kubernetes Service Manifest","Probe Tuning Best Practices","Production Best Practices","Frequently Asked Questions (FAQ)","  Django on Kubernetes: The Complete Production Guide  Deploying Django applications into production Kubernetes clusters requires harmonizing Django's application lifecycle with Kubernetes container orchestration: synchronizing database migrations, establishing robust probe lifecycles, and configuring isolated ports for health monitoring.   Production Deployment Manifest     apiVersion  :   apps\u002Fv1\n   kind  :   Deployment\n   metadata  :\n     name  :   django-app\n     labels  :\n       app  :   django-app\n   spec  :\n     replicas  :   3\n     selector  :\n       matchLabels  :\n         app  :   django-app\n     template  :\n       metadata  :\n         labels  :\n           app  :   django-app\n       spec  :\n         containers  :\n         -   name  :   django\n           image  :   my-registry.com\u002Fmy-django-app:v1.0.0\n           imagePullPolicy  :   IfNotPresent\n           command  :\n           -   \"python\"\n           -   \"manage.py\"\n           -   \"serve\"\n           -   \"--port=8000\"\n           -   \"--probe-port=8001\"\n           -   \"--check-migrations-apply\"\n           -   \"--req-queue-len=15\"\n           ports  :\n           -   name  :   http\n             containerPort  :   8000\n           -   name  :   probes\n             containerPort  :   8001\n           resources  :\n             requests  :\n               cpu  :   \"250m\"\n               memory  :   \"256Mi\"\n             limits  :\n               cpu  :   \"1000m\"\n               memory  :   \"512Mi\"\n           startupProbe  :\n             httpGet  :\n               path  :   \u002Fstartup\n               port  :   probes\n             initialDelaySeconds  :   2\n             periodSeconds  :   2\n             failureThreshold  :   30\n             timeoutSeconds  :   2\n           livenessProbe  :\n             httpGet  :\n               path  :   \u002Falive\n               port  :   probes\n             periodSeconds  :   5\n             timeoutSeconds  :   2\n             failureThreshold  :   3\n           readinessProbe  :\n             httpGet  :\n               path  :   \u002Fready\n               port  :   probes\n             periodSeconds  :   2\n             timeoutSeconds  :   2\n             failureThreshold  :   2\n   Kubernetes Service Manifest     apiVersion  :   v1\n   kind  :   Service\n   metadata  :\n     name  :   django-app-service\n   spec  :\n     type  :   ClusterIP\n     selector  :\n       app  :   django-app\n     ports  :\n     -   name  :   http\n       port  :   80\n       targetPort  :   http\n     -   name  :   metrics\n       port  :   8001\n       targetPort  :   probes\n   Probe Tuning Best Practices    Always Use a Startup Probe: \nWithout a startup probe, Kubernetes starts evaluating the liveness probe immediately upon container start. If Django takes 10 seconds to load models or apply database migrations, the liveness probe will kill the container before it finishes booting.   Set a Short Period for Readiness: \nConfigure   periodSeconds: 2  on   \u002Fready  so Kubernetes immediately sheds load when a worker pool experiences a congestion spike and restores traffic within 2 seconds of recovery.   Isolate Probes with   --probe-port : \nRunning probes on a dedicated port (e.g. 8001) prevents heavy file uploads or long-running queries on port 8000 from starving kubelet health check requests.   Production Best Practices  1. Sizing Workers and Threads: Cost Efficiency vs. Horizontal Scaling  Choosing the optimal worker and thread configuration depends on your cloud economics and scaling strategy:    Cost-Optimized Strategy (High Node Density): \nRunning larger Pods with higher concurrency (  --workers  and   --runtime-threads ) is substantially more cost-effective than running dozens of tiny micro-pods. Every additional Pod incurs Kubernetes baseline overhead (kubelet tracking, CoreDNS endpoint registrations, container runtime memory, CNI networking, and sidecar footprints). Sizing   --workers  to match your container's allocated CPU cores allows a single Pod to handle hundreds of concurrent requests, maximizing throughput per dollar and driving down cloud infrastructure bills.   Horizontal Autoscaling Strategy (Traffic Volatility): \nIf traffic is bursty or highly unpredictable, combine multi-worker Pods with the Horizontal Pod Autoscaler (HPA) to scale out replica counts smoothly under peak traffic waves.   Dynamic Sizing Defaults: \nBy default, Hurricane's Python worker threadpool automatically sizes to   min(32, CPUs + 4) . For ASGI mode,   --runtime-threads  automatically scales Tokio event loop threads across all allocated container CPU cores.  2. Zero-Downtime Rolling Deployments (  preStop  Hook)  When Kubernetes terminates a Pod during a rolling update, the endpoint removal in   kube-proxy  is asynchronous and takes a few seconds. If the application terminates immediately upon receiving   SIGTERM , clients may experience   502 Bad Gateway  errors.  Add a simple   preStop  sleep hook in your container spec to ensure zero-downtime traffic draining:     lifecycle  :\n     preStop  :\n       exec  :\n         command  : [  \"\u002Fbin\u002Fsh\"  ,   \"-c\"  ,   \"sleep 5\"  ]\n  This guarantees the Pod is completely removed from all Service and Ingress endpoints before Hurricane initiates its graceful shutdown and finishes in-flight requests.  3. Memory Guardrails vs. Kernel OOM Killer  If a memory leak occurs, the Linux kernel's Out-Of-Memory (OOM) killer abruptly terminates the container with an uncatchable   SIGKILL  (exit code 137).  To prevent unexpected crashes, set Hurricane's   --max-memory  parameter to approximately   75-80%  of the Pod's cgroup limit:     resources  :\n     limits  :\n       memory  :   \"512Mi\"\n   command  :\n   -   \"python\"\n   -   \"manage.py\"\n   -   \"serve\"\n   -   \"--max-memory=400\"\n  When worker RSS exceeds 400 MB, Hurricane initiates a graceful worker respawn without dropping in-flight requests.  4. Horizontal Pod Autoscaling (HPA)  Scale your deployment dynamically using CPU metrics or Hurricane's Prometheus queue backlog:     apiVersion  :   autoscaling\u002Fv2\n   kind  :   HorizontalPodAutoscaler\n   metadata  :\n     name  :   django-app-hpa\n   spec  :\n     scaleTargetRef  :\n       apiVersion  :   apps\u002Fv1\n       kind  :   Deployment\n       name  :   django-app\n     minReplicas  :   3\n     maxReplicas  :   20\n     metrics  :\n     -   type  :   Resource\n       resource  :\n         name  :   cpu\n         target  :\n           type  :   Utilization\n           averageUtilization  :   75\n   Frequently Asked Questions (FAQ)  How should Django database migrations be handled in Kubernetes?  Rather than relying on complex Helm pre-install hooks or fragile   initContainers  that run unconditionally on every replica, use Hurricane's   --check-migrations-apply  flag in the container command:     command  : [  \"python\"  ,   \"manage.py\"  ,   \"serve\"  ,   \"--check-migrations-apply\"  ]\n  This executes pending migrations during container initialization before marking   \u002Fstartup  healthy, ensuring no pod receives traffic until database schemas match the deployed code.  Why does Django need a Kubernetes startup probe?  Django applications often perform database migrations, model cache warming, and initial asset checks during boot. If only a liveness probe is configured with short timeouts, Kubernetes will kill the container while it is legitimately applying migrations. A   startupProbe  with a generous   failureThreshold: 60  and   periodSeconds: 2  grants up to 120 seconds for initialization while keeping steady-state liveness checks fast (e.g. 5 seconds).  How do you eliminate 502 Bad Gateway errors during rolling updates in Django?  When Kubernetes terminates an old pod,   kube-proxy  takes 2 to 5 seconds to propagate endpoint removal to the Ingress Controller. If your application terminates immediately upon   SIGTERM , clients whose requests are in transit receive   502 Bad Gateway . Adding a   lifecycle.preStop  hook with   sleep 5  ensures the pod stops receiving new ingress traffic before Hurricane finishes in-flight requests and exits.  How should I configure workers and concurrency for Django in Kubernetes?  For optimal cost efficiency, size worker threads (  --workers ) to match or slightly exceed the CPU cores allocated to your Pod. Running multi-worker concurrency per container maximizes throughput per node and drastically reduces cloud spend by avoiding the CPU and memory tax of spinning up unnecessary extra pods. For horizontal resilience, deploy at least 2–3 multi-worker replicas behind an HPA to ensure high availability during rolling updates.  How do you serve Django static and media files in Kubernetes without an Nginx sidecar?  Hurricane includes built-in static and media file serving directly in its Rust gateway (powered by   Granian ). Passing   --static  and   --media  enables Hurricane to serve assets directly from disk with sub-millisecond latency, completely eliminating the need for an auxiliary Nginx sidecar container in your Pod.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":52,"path":53,"dir":20,"title":36,"description":54,"keywords":55,"body":63},"content:1.guides:4.custom-metrics.md","\u002Fguides\u002Fcustom-metrics","Learn how to develop, register, and expose custom application and business Prometheus metrics using Hurricane's metric primitives and the official Prometheus Python client.",[56,57,58,59,60,61,62],"The 5 Metric Primitives","Developing Business & Operational Metrics: Code Examples","Tracking API Status Codes via Middleware","Instrumenting Outbound API Service Calls (2xx vs. 4xx vs. 5xx)","Updating Metrics via Django Signals","Scrape Output Example","Best Practices for Custom Prometheus Metrics","  Custom Prometheus Metrics  Django Hurricane includes an integrated Prometheus metrics exporter running directly inside its gateway and probe application. Beyond the built-in system metrics (request counts, latency averages, and queue lengths), Hurricane provides a declarative framework for defining and exporting custom application, operational, and business metrics.  Hurricane integrates seamlessly with the    official prometheus_client Python library  (  documentation ), allowing you to combine Hurricane's high-level metric primitives with low-level labeled Prometheus collectors.   The 5 Metric Primitives  Hurricane provides five base metric primitives in   hurricane.metrics :     Metric Class  Prometheus Type  When to Use  Update Mechanism      CounterMetric  Counter  Monotonically increasing events (e.g. user signups, orders placed, failed logins).   MyCounter.increment(amount=1)     StoredMetric  Gauge  Values that fluctuate over time (e.g. active users, worker threads, cache size).   MyGauge.set(value)     CalculatedMetric  Gauge \u002F Computed  Values computed on-demand when   \u002Fmetrics  is scraped (e.g. database query counts).  Dynamic inside   get_value(*args)     AverageMetric  Summary \u002F Average  Running arithmetic mean updated per request (e.g. average basket value, cart size).   MyAverage.add_value(val)     ObservedMetric  Histogram  Latency distributions and percentile buckets (e.g. external payment gateway response times).   MyHistogram.observe(val)   Developing Business & Operational Metrics: Code Examples  Create a dedicated   metrics.py  inside your Django application:     from   django.core.cache   import   cache\n   from   prometheus_client   import   Counter, Histogram\n   from   hurricane.metrics   import   (\n       AverageMetric,\n       CalculatedMetric,\n       CounterMetric,\n       ObservedMetric,\n       StoredMetric,\n   )\n   from   hurricane.metrics.registry   import   registry\n   from   myapp.models   import   Order, UserProfile\n   \n   \n   # ==============================================================================\n   # 1. Business Metrics: Open Orders & Financial Pipeline\n   # ==============================================================================\n   \n   \n   class   OpenOrdersMetric  (  CalculatedMetric  ):\n       \"\"\"\n       Computes total open orders requiring fulfillment.\n       Demonstrates caching pattern to avoid hammering database during frequent Prometheus scrapes.\n       \"\"\"\n   \n       code   =   \"ecommerce_open_orders_total\"\n       description   =   \"Current number of open orders requiring warehouse fulfillment\"\n   \n       @  classmethod\n       def   get_value  (cls,   *  args):\n           # Cache count for 15 seconds so multiple scraper pods or rapid scrapes don't overload DB\n           def   fetch_count  ():\n               return   Order.objects.filter(  status__in  =  [  \"pending\"  ,   \"processing\"  ]).count()\n   \n           return   cache.get_or_set(  \"metric_open_orders_count\"  , fetch_count,   timeout  =  15  )\n   \n   \n   class   HighValueOrdersMetric  (  CalculatedMetric  ):\n       \"\"\"Orders with total value exceeding $1,000.\"\"\"\n   \n       code   =   \"ecommerce_high_value_orders_pending\"\n       description   =   \"Number of pending high-priority orders above $1,000\"\n   \n       @  classmethod\n       def   get_value  (cls,   *  args):\n           return   Order.objects.filter(  status  =  \"processing\"  ,   total_amount__gte  =  1000  ).count()\n   \n   \n   # ==============================================================================\n   # 2. Business Metrics: User Segmentation & Account Attributes\n   # ==============================================================================\n   \n   \n   class   EnterpriseUsersMetric  (  CalculatedMetric  ):\n       \"\"\"Tracks count of active enterprise-tier subscribers.\"\"\"\n   \n       code   =   \"app_users_enterprise_tier_count\"\n       description   =   \"Active accounts on the enterprise subscription tier\"\n   \n       @  classmethod\n       def   get_value  (cls,   *  args):\n           return   UserProfile.objects.filter(  is_active  =  True  ,   tier  =  \"enterprise\"  ).count()\n   \n   \n   class   PendingVerificationUsersMetric  (  CalculatedMetric  ):\n       \"\"\"Tracks onboarding friction by counting users pending KYC or email verification.\"\"\"\n   \n       code   =   \"app_users_pending_verification_count\"\n       description   =   \"Accounts awaiting KYC or identity verification\"\n   \n       @  classmethod\n       def   get_value  (cls,   *  args):\n           return   UserProfile.objects.filter(  is_active  =  True  ,   kyc_verified  =  False  ).count()\n   \n   \n   # ==============================================================================\n   # 3. Operational Metrics: Multi-Dimensional API Status Counters (200 vs 400 vs 500)\n   # ==============================================================================\n   \n   # Using the official prometheus_client Counter with multidimensional labels\n   # Docs: https:\u002F\u002Fprometheus.github.io\u002Fclient_python\u002Finstrumenting\u002Flabels\u002F\n   EXTERNAL_API_REQUESTS   =   Counter(\n       \"external_api_http_requests_total\"  ,\n       \"Total outgoing HTTP requests to external partner APIs partitioned by target and HTTP status\"  ,\n       labelnames  =  [  \"service\"  ,   \"method\"  ,   \"status_class\"  ],\n   )\n   \n   DJANGO_HTTP_REQUESTS   =   Counter(\n       \"django_http_requests_total\"  ,\n       \"Total HTTP requests handled by Django grouped by endpoint, method, and HTTP status code\"  ,\n       labelnames  =  [  \"endpoint\"  ,   \"method\"  ,   \"status_code\"  ],\n   )\n   \n   \n   # ==============================================================================\n   # 4. Latency Distribution & Moving Averages\n   # ==============================================================================\n   \n   \n   class   PaymentGatewayLatencyMetric  (  ObservedMetric  ):\n       code   =   \"ecommerce_payment_latency_seconds\"\n       description   =   \"Response time distribution for third-party payment processing (Stripe\u002FPayPal)\"\n       prometheus   =   Histogram(\n           \"ecommerce_payment_latency_seconds\"  ,\n           \"Payment gateway latency in seconds\"  ,\n           buckets  =  (  0.05  ,   0.1  ,   0.25  ,   0.5  ,   1.0  ,   2.5  ,   5.0  ),\n       )\n   \n   \n   class   AverageOrderValueMetric  (  AverageMetric  ):\n       code   =   \"ecommerce_order_value_average_dollars\"\n       description   =   \"Running average dollar amount per completed order\"\n   \n   \n   # Register Hurricane metrics\n   registry.register(OpenOrdersMetric)\n   registry.register(HighValueOrdersMetric)\n   registry.register(EnterpriseUsersMetric)\n   registry.register(PendingVerificationUsersMetric)\n   registry.register(PaymentGatewayLatencyMetric)\n   registry.register(AverageOrderValueMetric)\n   Tracking API Status Codes via Middleware  To record all incoming HTTP traffic and classify responses by status code (   200 ,    400 ,    500 , etc.), implement a lightweight Django middleware:     import   time\n   from   myapp.metrics   import   DJANGO_HTTP_REQUESTS\n   \n   \n   class   PrometheusApiMetricsMiddleware  :\n       \"\"\"\n       Middleware that records HTTP status codes and endpoint metrics\n       into Prometheus counters with dimensional labels.\n       \"\"\"\n   \n       def   __init__  (self, get_response):\n           self  .get_response   =   get_response\n   \n       def   __call__  (self, request):\n           response   =   self  .get_response(request)\n   \n           # Sanitize path to prevent high-cardinality label explosion with raw UUIDs\u002FIDs\n           # E.g. \u002Fapi\u002Forders\u002F123 -> \u002Fapi\u002Forders\n           url_name   =   getattr  (request.resolver_match,   \"url_name\"  ,   None  )   if   request.resolver_match   else   None\n           endpoint   =   url_name   or   request.path[:  32  ]\n   \n           DJANGO_HTTP_REQUESTS  .labels(\n               endpoint  =  endpoint,\n               method  =  request.method,\n               status_code  =  str  (response.status_code),\n           ).inc()\n   \n           return   response\n  Add the middleware to   settings.py :     MIDDLEWARE   =   [\n       # Add near the top to capture all responses\n       \"myapp.middleware.PrometheusApiMetricsMiddleware\"  ,\n       # ... other middlewares\n   ]\n   Instrumenting Outbound API Service Calls (2xx vs. 4xx vs. 5xx)  When calling external microservices or third-party APIs (Stripe, Twilio, SendGrid), record the result using status class labels:     import   time\n   import   requests\n   from   myapp.metrics   import   EXTERNAL_API_REQUESTS  , PaymentGatewayLatencyMetric\n   \n   \n   def   process_external_payment  (amount:   float  , customer_id:   str  ) ->   dict  :\n       url   =   \"https:\u002F\u002Fapi.payments.example.com\u002Fv1\u002Fcharges\"\n       start_time   =   time.perf_counter()\n   \n       try  :\n           response   =   requests.post(url,   json  =  {  \"amount\"  : amount,   \"customer\"  : customer_id},   timeout  =  3.0  )\n           status_class   =   f  \"  {  response.status_code   \u002F\u002F   100}  xx\"\n           status_code   =   response.status_code\n           data   =   response.json()\n       except   requests.exceptions.Timeout:\n           status_class   =   \"timeout\"\n           data   =   {  \"error\"  :   \"Payment service timed out\"  }\n       except   requests.exceptions.RequestException:\n           status_class   =   \"network_error\"\n           data   =   {  \"error\"  :   \"Payment network connection failed\"  }\n       finally  :\n           duration   =   time.perf_counter()   -   start_time\n           # Record metrics\n           EXTERNAL_API_REQUESTS  .labels(\n               service  =  \"payments_gateway\"  ,\n               method  =  \"POST\"  ,\n               status_class  =  status_class,\n           ).inc()\n           PaymentGatewayLatencyMetric.observe(duration)\n   \n       return   data\n   Updating Metrics via Django Signals  Use Django signals to reactively adjust gauges and counters when models change:     from   django.db.models.signals   import   post_save\n   from   django.dispatch   import   receiver\n   from   myapp.models   import   Order\n   from   myapp.metrics   import   AverageOrderValueMetric\n   \n   \n   @receiver  (post_save,   sender  =  Order)\n   def   on_order_created  (sender, instance, created,   **  kwargs):\n       if   created   and   instance.status   ==   \"completed\"  :\n           # Update running transaction average\n           AverageOrderValueMetric.add_value(  float  (instance.total_amount))\n   Scrape Output Example  Once registered, all custom and standard Prometheus client metrics are exported on   \u002Fmetrics  (probe port   8001 ):     curl   -s   http:\u002F\u002F127.0.0.1:8001\u002Fmetrics   |   grep   -E   \"ecommerce|app_users|django_http|external_api\"\n   Exposition Output:     # HELP ecommerce_open_orders_total Current number of open orders requiring warehouse fulfillment\n   # TYPE ecommerce_open_orders_total gauge\n   ecommerce_open_orders_total 14.0\n   \n   # HELP ecommerce_high_value_orders_pending Number of pending high-priority orders above $1,000\n   # TYPE ecommerce_high_value_orders_pending gauge\n   ecommerce_high_value_orders_pending 3.0\n   \n   # HELP app_users_enterprise_tier_count Active accounts on the enterprise subscription tier\n   # TYPE app_users_enterprise_tier_count gauge\n   app_users_enterprise_tier_count 142.0\n   \n   # HELP app_users_pending_verification_count Accounts awaiting KYC or identity verification\n   # TYPE app_users_pending_verification_count gauge\n   app_users_pending_verification_count 27.0\n   \n   # HELP django_http_requests_total Total HTTP requests handled by Django grouped by endpoint, method, and HTTP status code\n   # TYPE django_http_requests_total counter\n   django_http_requests_total{endpoint=\"order-create\",method=\"POST\",status_code=\"201\"} 320.0\n   django_http_requests_total{endpoint=\"order-create\",method=\"POST\",status_code=\"400\"} 12.0\n   django_http_requests_total{endpoint=\"checkout-view\",method=\"POST\",status_code=\"500\"} 1.0\n   django_http_requests_total{endpoint=\"api-user-detail\",method=\"GET\",status_code=\"200\"} 1845.0\n   django_http_requests_total{endpoint=\"api-user-detail\",method=\"GET\",status_code=\"404\"} 43.0\n   \n   # HELP external_api_http_requests_total Total outgoing HTTP requests to external partner APIs\n   # TYPE external_api_http_requests_total counter\n   external_api_http_requests_total{method=\"POST\",service=\"payments_gateway\",status_class=\"2xx\"} 318.0\n   external_api_http_requests_total{method=\"POST\",service=\"payments_gateway\",status_class=\"4xx\"} 9.0\n   external_api_http_requests_total{method=\"POST\",service=\"payments_gateway\",status_class=\"5xx\"} 2.0\n   \n   # HELP ecommerce_payment_latency_seconds Payment gateway latency in seconds\n   # TYPE ecommerce_payment_latency_seconds histogram\n   ecommerce_payment_latency_seconds_bucket{le=\"0.1\"} 42.0\n   ecommerce_payment_latency_seconds_bucket{le=\"0.5\"} 310.0\n   ecommerce_payment_latency_seconds_bucket{le=\"1.0\"} 325.0\n   ecommerce_payment_latency_seconds_bucket{le=\"+Inf\"} 329.0\n   ecommerce_payment_latency_seconds_count 329.0\n   ecommerce_payment_latency_seconds_sum 42.18\n   Best Practices for Custom Prometheus Metrics    Beware of Label Cardinality :\nNever use unbounded high-cardinality values (such as raw UUIDs, email addresses, or un-sanitized URLs) as label values in Prometheus counters or histograms. High cardinality causes memory explosion in both the application process and Prometheus TSDB. Always group or sanitize endpoints (e.g.   request.resolver_match.url_name ).   Cache Heavy Calculated Queries :\nBecause Prometheus scrapes   \u002Fmetrics  at regular intervals (typically every 10–30s), a   CalculatedMetric  that performs full table scans or un-indexed queries can impact database performance. Cache query results with   cache.get_or_set(..., timeout=15)  to avoid duplicate computation across concurrent scrapes.   Use the Standard Python Client When Labels are Required :\nWhen you need multi-dimensional labels (such as   {service=\"...\", status_code=\"...\"} ), use   prometheus_client.Counter  or   prometheus_client.Gauge  directly. Hurricane automatically includes all collectors registered in the default   prometheus_client.REGISTRY .   Learn More :\n   Official Python Library:    prometheus_client on GitHub  Official Documentation:    prometheus_client Documentation  Prometheus Guidelines:    Metric and Label Naming Best Practices  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":65,"path":66,"dir":20,"title":67,"description":68,"keywords":69,"body":74},"content:1.guides:5.reverse-proxies.md","\u002Fguides\u002Freverse-proxies","Reverse Proxies & Ingress","Configure Hurricane behind Nginx, Traefik, AWS ALB, Cloudflare, and Kubernetes Ingress with proper client IP resolution and defense tuning.",[70,71,72,73],"Client IP Resolution & Trusted Headers","Production Nginx Configuration","Kubernetes Ingress Configuration","Tuning Fast-404 Behind Reverse Proxies","  Reverse Proxies & Ingress Guide  In production environments, Django Hurricane typically operates behind an edge reverse proxy, CDN, or Kubernetes Ingress Controller (such as Nginx, Traefik, AWS ALB, or Cloudflare).  This guide covers configuring proxy headers, resolving real client IPs for the   Rate Limiter , and optimizing   Fast-404  defense shields.   Client IP Resolution & Trusted Headers  Hurricane's Token-Bucket Rate Limiter tracks request frequency per client IP address. When operating behind a reverse proxy, the direct socket connection (  REMOTE_ADDR ) belongs to the proxy rather than the end user.  To prevent all users from sharing a single proxy rate-limit bucket, configure   RATE_LIMIT_PROXY_HEADER  to match your infrastructure provider:     Infrastructure Provider  Recommended Proxy Header  Hurricane Setting     Standard Reverse Proxy (Nginx, Traefik)   X-Forwarded-For  (first IP)   RATE_LIMIT_PROXY_HEADER = \"X-Forwarded-For\"    Cloudflare   CF-Connecting-IP   RATE_LIMIT_PROXY_HEADER = \"CF-Connecting-IP\"    Nginx (Direct)   X-Real-IP   RATE_LIMIT_PROXY_HEADER = \"X-Real-IP\"    AWS Application Load Balancer (ALB)   X-Forwarded-For   RATE_LIMIT_PROXY_HEADER = \"X-Forwarded-For\"    Google Cloud Load Balancer (GCLB)   X-Forwarded-For   RATE_LIMIT_PROXY_HEADER = \"X-Forwarded-For\"  Configuration Example  In your   settings.py :     # Cloudflare example:\n   RATE_LIMIT_PROXY_HEADER   =   \"CF-Connecting-IP\"\n   \n   # Or via environment variable:\n   # HURRICANE_RATE_LIMIT_PROXY_HEADER=\"CF-Connecting-IP\"\n  Hurricane automatically normalizes header formats—whether you specify   \"CF-Connecting-IP\"  or   \"HTTP_CF_CONNECTING_IP\" , it correctly locates the value in WSGI\u002FASGI request headers.   Production Nginx Configuration  Below is an optimal Nginx configuration proxying traffic to Hurricane on port 8000 while maintaining real client headers and supporting WebSockets:     upstream hurricane_upstream {\n       server 127.0.0.1:8000;\n       keepalive 32;\n   }\n   \n   server {\n       listen 80;\n       server_name example.com;\n   \n       client_max_body_size 50M;\n   \n       location \u002F {\n           proxy_pass http:\u002F\u002Fhurricane_upstream;\n           proxy_http_version 1.1;\n   \n           # WebSocket support\n           proxy_set_header Upgrade $http_upgrade;\n           proxy_set_header Connection $connection_upgrade;\n   \n           # Real Client IP and Host headers\n           proxy_set_header Host $host;\n           proxy_set_header X-Real-IP $remote_addr;\n           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n           proxy_set_header X-Forwarded-Proto $scheme;\n   \n           # Timeouts and buffer sizes\n           proxy_connect_timeout 5s;\n           proxy_read_timeout 60s;\n           proxy_send_timeout 60s;\n       }\n   }\n   Kubernetes Ingress Configuration  When deploying inside Kubernetes with   ingress-nginx , ensure snippet or annotation settings pass real client IPs:     apiVersion  :   networking.k8s.io\u002Fv1\n   kind  :   Ingress\n   metadata  :\n     name  :   django-app-ingress\n     annotations  :\n       kubernetes.io\u002Fingress.class  :   \"nginx\"\n       nginx.ingress.kubernetes.io\u002Fproxy-body-size  :   \"50m\"\n       nginx.ingress.kubernetes.io\u002Fproxy-read-timeout  :   \"60\"\n       nginx.ingress.kubernetes.io\u002Fproxy-send-timeout  :   \"60\"\n   spec  :\n     rules  :\n     -   host  :   app.example.com\n       http  :\n         paths  :\n         -   path  :   \u002F\n           pathType  :   Prefix\n           backend  :\n             service  :\n               name  :   django-app-service\n               port  :\n                 number  :   80\n   Tuning Fast-404 Behind Reverse Proxies  Hurricane's   Fast-404 Security Shield  blocks scanner probes and malicious paths before they reach Django. Choose the optimal strategy based on your routing architecture:  1.   auto  Strategy (Default)  Inspects Django's root   urls.py . If a root catch-all pattern is detected (e.g. Wagtail, CMS, or dynamic routing), it operates in   Signature-only mode  to avoid dropping legitimate dynamic pages. Otherwise, it operates in high-performance   Prefix mode .  2.   prefix  Strategy  Ideal for dedicated APIs, microservices, and applications with explicit URL prefixes. Any path that does not match a known Django URL prefix is dropped immediately with an instant 404.     FAST_404   =   \"prefix\"\n   FAST_404_EXTRA_PREFIXES   =   [  \"api\"  ,   \"auth\"  ,   \"v1\"  ,   \"v2\"  ]\n  3.   signature  Strategy  Strictly checks incoming paths against known malicious exploit patterns (  .php ,   .env ,   \u002Fwp-admin\u002F ,   phpmyadmin , etc.). Legitimate non-matching paths continue to Django. Recommended when running CMS or dynamic multi-tenant routes.     FAST_404   =   \"signature\"\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":76,"path":77,"dir":20,"title":78,"description":79,"keywords":80,"body":89},"content:1.guides:6.static-and-media-files.md","\u002Fguides\u002Fstatic-and-media-files","Static & Media Files Architecture","High-performance static and media file serving with Granian: zero-copy native Rust serving, dynamic finders fallback for development, and automated collectstatic workflows.",[81,82,83,84,85,86,87,88],"The Three-Tier Architecture","Tier 1: Production (Granian Native Rust Engine)","Container Image Build Recommendations for collectstatic","Tier 2: Development & Staging (Zero-Setup Dynamic Finders)","Tier 3: Automated Startup Collection (--collectstatic)","Development with --autoreload and --static-watch","Serving Media Files (--media)","HTTP Caching & Conditional Requests","  Static & Media Files Architecture  In traditional Django Kubernetes deployments, serving static and user-uploaded media files typically requires running a separate   Nginx sidecar container  inside every pod, or configuring external reverse proxy ingress controllers with complex volume mounts.  Hurricane completely eliminates the need for Nginx sidecars by incorporating a   Three-Tier Static & Media File Architecture  powered by Granian's native Rust file streaming engine combined with Django's static finders.   The Three-Tier Architecture     graph TD\n       Req[\"HTTP Request for \u002Fstatic\u002F or \u002Fmedia\u002F\"] --> MountCheck{\"Granian Native Mount Active?\u003Cbr\u002F>(STATIC_ROOT populated & not DEBUG)\"}\n       MountCheck -- Yes --> RustServe[\"Tier 1: Granian Rust Engine\u003Cbr\u002F>Nginx-grade speed &lt; 20µs\u003Cbr\u002F>Zero Python GIL overhead\u003Cbr\u002F>Kernel sendfile & HTTP Caching\"]\n       MountCheck -- No --> PythonGW[\"Tier 2: Hurricane Python Gateway\"]\n       PythonGW --> DiskCheck{\"File exists in\u003Cbr\u002F>STATIC_ROOT or MEDIA_ROOT?\"}\n       DiskCheck -- Yes --> StreamPython[\"Stream from Disk with ETag &\u003Cbr\u002F>HTTP 304 Not Modified\"]\n       DiskCheck -- No --> FindersCheck{\"django.contrib.staticfiles\u003Cbr\u002F>finders.find()?\"}\n       FindersCheck -- Yes --> StreamFinder[\"Dynamic App \u002F STATICFILES_DIRS\u003Cbr\u002F>Development Mode &lt; 1ms\u003Cbr\u002F>No collectstatic needed!\"]\n       FindersCheck -- No --> NotFound[\"HTTP 404 Not Found\"]\n   Tier 1: Production (Granian Native Rust Engine)  The \"Nginx Replacement\"  When   --static  is passed and   settings.STATIC_ROOT  exists and contains collected files:   Hurricane automatically configures Granian's native Rust static server:\n    static_path_route : Mounted at   STATIC_URL  (e.g.   \"\u002Fstatic\" ).   static_path_mount : Bound directly to the absolute filesystem path   STATIC_ROOT .   static_path_expires : Configured with   Cache-Control: max-age=86400  (or   HURRICANE_STATIC_CACHE_EXPIRES ).  Requests for   \u002Fstatic\u002F*  are intercepted   directly in Rust\u002FTokio at the socket layer .  The request   never enters the Python runtime , never acquires the Python GIL, and consumes   zero Python heap memory .  Achieves throughput and latency identical to Nginx (  \u003C 20 microseconds ).   Container Image Build Recommendations for   collectstatic  Compiling static files in containerized environments requires balancing build reproducibility, pod startup speed, and cluster security.  1. Always Run   collectstatic  During   docker build  (Not at Pod Boot)  Running   collectstatic  inside a Kubernetes container entrypoint or pod lifecycle hook is an anti-pattern:    Instant Pod Startup (\u003C100ms vs 15–40s) : Compiling static files during pod boot delays Kubernetes   startupProbe  and   readinessProbe  completion. During Horizontal Pod Autoscaling (HPA) traffic spikes or rolling deployments, this causes ingress delays and 502\u002F504 errors.   Immutable Container Security (  readOnlyRootFilesystem ) : Production Kubernetes security benchmarks (CIS Kubernetes Benchmark) require   securityContext.readOnlyRootFilesystem: true . Pods running with a read-only root filesystem cannot write to   STATIC_ROOT  at runtime.   Concurrency & Multi-Replica Race Conditions : When deploying 5 or 50 pod replicas simultaneously, multiple pods executing   collectstatic  concurrently against shared volumes or manifest files can corrupt the static manifest or trigger filesystem deadlocks.   2. Solving the \"No Database at Build Time\" Dilemma  A common hurdle during   docker build  is that Django's   settings.py  attempts to connect to a database or fails if secrets (like   SECRET_KEY  or   DATABASE_URL ) are missing. Because the production database is not accessible during CI\u002FCD image builds,   RUN python manage.py collectstatic  can fail.   Best Practice:  Provide dummy fallback environment variables specifically for the build step in your   Dockerfile :     # Supply safe build-time dummies so Django initializes without a live database\n   RUN   SECRET_KEY=  \"build-dummy-key\"   \\\n       DATABASE_URL=  \"sqlite:\u002F\u002F\u002F:memory:\"   \\\n       python manage.py collectstatic --noinput\n  Alternatively, configure defensive fallbacks in your   settings.py :     # Allow building without live database credentials\n   SECRET_KEY   =   os.environ.get(  \"SECRET_KEY\"  ,   \"build-time-insecure-dummy-key\"  )\n   \n   DATABASES   =   {\n       \"default\"  : dj_database_url.config(\n           default  =  os.environ.get(  \"DATABASE_URL\"  ,   \"sqlite:\u002F\u002F\u002F:memory:\"  ),\n           conn_max_age  =  600  ,\n       )\n   }\n   3. Production Multi-Stage Dockerfile Blueprint  Here is the recommended multi-stage   Dockerfile  pattern combining frontend building (Vite \u002F Tailwind \u002F Node), modern Python dependency resolution (  uv ), and Hurricane native static serving:     # ====================================================================\n   # Stage 1: Build Frontend Assets (Node.js \u002F Vite \u002F Tailwind)\n   # ====================================================================\n   FROM   node:20-alpine   AS   frontend-builder\n   WORKDIR   \u002Fapp\n   COPY   package*.json .\u002F\n   RUN   npm ci\n   COPY   frontend\u002F .\u002Ffrontend\u002F\n   RUN   npm run build  # Generates compiled bundles in \u002Fapp\u002Fstatic\u002Fdist\u002F\n   \n   # ====================================================================\n   # Stage 2: Install Python Dependencies via uv\n   # ====================================================================\n   FROM   python:3.12-slim   AS   builder\n   WORKDIR   \u002Fapp\n   \n   # Install Astral uv for ultra-fast, reproducible dependency builds\n   COPY   --from=ghcr.io\u002Fastral-sh\u002Fuv:latest \u002Fuv \u002Fbin\u002Fuv\n   COPY   pyproject.toml uv.lock .\u002F\n   RUN   uv sync --frozen --no-dev --no-install-project\n   \n   # ====================================================================\n   # Stage 3: Final Production Runtime Image\n   # ====================================================================\n   FROM   python:3.12-slim\n   WORKDIR   \u002Fapp\n   \n   # Copy virtualenv and application code\n   COPY   --from=builder \u002Fapp\u002F.venv \u002Fapp\u002F.venv\n   ENV   PATH=  \"\u002Fapp\u002F.venv\u002Fbin:$PATH\"\n   COPY   . \u002Fapp\u002F\n   \n   # Copy compiled frontend bundles from Stage 1 into Django's static directory\n   COPY   --from=frontend-builder \u002Fapp\u002Fstatic\u002Fdist \u002Fapp\u002Fstatic\u002Fdist\n   \n   # Pre-compile static assets into STATIC_ROOT\n   RUN   SECRET_KEY=  \"build-time-dummy\"   \\\n       DATABASE_URL=  \"sqlite:\u002F\u002F\u002F:memory:\"   \\\n       python manage.py collectstatic --noinput --clear\n   \n   # Run as non-root user for Kubernetes security\n   USER   10001:10001\n   \n   # Start Hurricane with Granian native static serving enabled\n   EXPOSE   8000 8001\n   CMD   [  \"python\"  ,   \"manage.py\"  ,   \"serve\"  ,   \"--static\"  ,   \"--port=8000\"  ,   \"--probe-port=8001\"  ]\n   4. Cache-Busting with   ManifestStaticFilesStorage  For optimal browser performance, configure Django's manifest storage in   settings.py :     STATICFILES_STORAGE   =   \"django.contrib.staticfiles.storage.ManifestStaticFilesStorage\"\n   # Or WhiteNoise's compressed manifest storage if you pre-compress with gzip\u002Fbrotli:\n   # STATICFILES_STORAGE = \"whitenoise.storage.CompressedManifestStaticFilesStorage\"\n   When   collectstatic  runs, it appends unique MD5 hashes to filenames (e.g.   main.bf72a1.css ).  Granian's native Rust mount serves these with   static_path_expires=31536000  (1 year), ensuring browsers cache assets permanently without stale-cache issues.   5. When Should You Use the   --collectstatic  CLI Flag?  While compiling static files during   docker build  is standard for production, Hurricane provides the   --collectstatic  flag (and   HURRICANE_COLLECTSTATIC=True ) for specific environments:    Ephemeral Staging & Preview Environments : Quick QA or feature-branch deployments where building a multi-stage Docker image per branch is not desired.   Local Docker Compose : When mounting host code directories (  volumes: [.:\u002Fapp] ) where   STATIC_ROOT  must be regenerated on container boot.   Automated CI\u002FCD Test Runners : Running test suites or smoke tests where a temporary static build is needed before execution.   Tier 2: Development & Staging (Zero-Setup Dynamic Finders)  In local development or ephemeral staging environments, running   collectstatic  every time you edit a CSS or JavaScript file is cumbersome.  How Dynamic Serving Works  If   STATIC_ROOT  is empty, does not exist, or   settings.DEBUG = True :   Hurricane detects that native Rust mounting is not appropriate.  The gateway activates   Dynamic Finders Fallback .  When   \u002Fstatic\u002Fapp\u002Fstyle.css  is requested, Hurricane queries   django.contrib.staticfiles.finders.find() :\n   Searches   settings.STATICFILES_DIRS  (e.g. frontend directories).  Searches all   INSTALLED_APPS  (e.g.   django.contrib.admin\u002Fstatic\u002Fadmin\u002F , third-party packages, custom apps).  Files are served dynamically with proper MIME types,   ETag , and   Last-Modified  headers.  Live Editing Without Restarts  In development, run:     python   manage.py   serve   --static   --autoreload\n  Any edit to an asset in   STATICFILES_DIRS  or an app directory is   immediately visible upon refreshing your browser —no server reload and no   collectstatic  execution required!   Tier 3: Automated Startup Collection (  --collectstatic )  If you run single-container deployments or staging pods where you want Granian's native Rust speed but do not want a separate Docker build step:  Pass   --collectstatic  (or set   HURRICANE_COLLECTSTATIC=True ):     python   manage.py   serve   --static   --collectstatic\n  Execution Lifecycle   Hurricane executes Django's   call_command(\"collectstatic\", interactive=False, clear=False)  during pre-flight startup before the server socket binds.  All static assets from all apps and   STATICFILES_DIRS  are gathered into   STATIC_ROOT .  Granian detects the newly populated   STATIC_ROOT  and binds the native Rust mount.  The server begins handling traffic at full native Rust speed.   Development with   --autoreload  and   --static-watch  When developing modern web apps with build tools (Webpack, Vite, Tailwind CSS, esbuild) that compile frontend assets into a distribution folder:     python   manage.py   serve   --static   --collectstatic   --autoreload   --static-watch   frontend\u002Fdist\n  What Happens:    --autoreload : Enables Granian's file system watcher.   --static-watch frontend\u002Fdist : Instructs Granian to watch   frontend\u002Fdist\u002F  in addition to Python source files.  When your frontend tool rebuilds assets in   frontend\u002Fdist\u002F , Granian detects the change and triggers a fast worker reload.  On reload,   --collectstatic  synchronizes the new bundles into   STATIC_ROOT .   Serving Media Files (  --media )  User-uploaded media files (avatars, document attachments) stored in   settings.MEDIA_ROOT  are enabled via   --media  (or   HURRICANE_MEDIA=True ):     python   manage.py   serve   --static   --media\n   When   MEDIA_ROOT  exists, Granian mounts   MEDIA_URL  (e.g.   \u002Fmedia ) directly in Rust.  Uploaded files are served at native speed with directory traversal protection.   HTTP Caching & Conditional Requests  When static or media assets are served through Hurricane's Python gateway (e.g. in dev or staging), Hurricane automatically emits production-grade HTTP caching headers:     ETag : Deterministic file fingerprint based on inode modification time and byte length (  \"{mtime}-{size}\" ).    Last-Modified : Formatted RFC 7231 GMT date.    Cache-Control :   public, max-age=86400  in production;   no-cache  when   settings.DEBUG = True .    304 Not Modified : Evaluates incoming   If-None-Match  and   If-Modified-Since  headers. When matched, returns   HTTP 304  with zero payload body, saving network bandwidth.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":91,"path":92,"dir":20,"title":93,"description":94,"keywords":95,"body":100},"content:1.guides:7.standalone-and-cloud-deployments.md","\u002Fguides\u002Fstandalone-and-cloud-deployments","Standalone, Docker & Cloud Deployments","Deploying Hurricane outside Kubernetes: Docker Compose, Systemd virtual machines, and Cloud PaaS (Fly.io, AWS ECS, Render).",[96,97,98,99],"1. Docker Compose (Zero-Nginx Single Service)","2. Virtual Machines & Bare Metal (Systemd)","3. Cloud PaaS (Fly.io, AWS ECS, Render)","Port Strategy: Combined vs. Isolated Probes","  Standalone, Docker & Cloud Deployments  While Hurricane provides first-class, premier integration for Kubernetes clusters, it is fundamentally a   Django-Native Application Server .  You do   not  need Kubernetes to take advantage of Hurricane's Rust-powered performance, built-in edge security shields, native static asset streaming, and health probe endpoints. Hurricane runs seamlessly on single-container Docker setups, cloud PaaS platforms, and traditional virtual machines.   1. Docker Compose (Zero-Nginx Single Service)  In standard Django setups, developers often spin up multiple containers: Django, Gunicorn, and an Nginx reverse proxy just to serve static files.  With Hurricane's native static file streaming and built-in rate limiting,   you do not need an Nginx container :     version  :   \"3.9\"\n   \n   services  :\n     db  :\n       image  :   postgres:16-alpine\n       environment  :\n         POSTGRES_DB  :   myapp\n         POSTGRES_USER  :   postgres\n         POSTGRES_PASSWORD  :   secretpassword\n       volumes  :\n         -   postgres_data:\u002Fvar\u002Flib\u002Fpostgresql\u002Fdata\n       healthcheck  :\n         test  : [  \"CMD-SHELL\"  ,   \"pg_isready -U postgres\"  ]\n         interval  :   5s\n         timeout  :   3s\n         retries  :   5\n   \n     web  :\n       build  :   .\n       command  :   >\n         python manage.py serve\n         --port=8000\n         --static\n         --media\n         --check-migrations-apply\n       ports  :\n         -   \"8000:8000\"\n       environment  :\n         DATABASE_URL  :   postgres:\u002F\u002Fpostgres:secretpassword@db:5432\u002Fmyapp\n         HURRICANE_FAST_404  :   \"auto\"\n         HURRICANE_RATE_LIMIT  :   \"true\"\n       depends_on  :\n         db  :\n           condition  :   service_healthy\n       healthcheck  :\n         # Hurricane isolates probes on port 8001 by default (port + 1)\n         test  : [  \"CMD\"  ,   \"python\"  ,   \"-c\"  ,   \"import urllib.request; urllib.request.urlopen('http:\u002F\u002F127.0.0.1:8001\u002Falive')\"  ]\n         interval  :   10s\n         timeout  :   2s\n         retries  :   3\n   \n   volumes  :\n     postgres_data  :\n  Why This Is Better:    One Web Container : Eliminates Nginx configuration files, socket volumes, and permission mismatches.   Automated Healthchecks : Docker's   healthcheck  directly queries Hurricane's   \u002Falive  probe.   Preflight Migration Safety :   --check-migrations-apply  automatically verifies database connectivity and applies schema migrations before accepting HTTP requests.   2. Virtual Machines & Bare Metal (Systemd)  If you deploy Django directly to virtual private servers (Hetzner, DigitalOcean, AWS EC2, Linode) using   systemd , Hurricane replaces Gunicorn, Uvicorn, and local Nginx reverse proxies.  Create a systemd service file at   \u002Fetc\u002Fsystemd\u002Fsystem\u002Fdjango.service :     [Unit]\n   Description  =Django Hurricane Application Server\n   After  =network.target postgresql.service\n   \n   [Service]\n   Type  =simple\n   User  =django\n   Group  =django\n   WorkingDirectory  =\u002Fvar\u002Fwww\u002Fmyapp\n   EnvironmentFile  =\u002Fvar\u002Fwww\u002Fmyapp\u002F.env\n   \n   # Execute Hurricane directly from your Python virtualenv\n   ExecStart  =\u002Fvar\u002Fwww\u002Fmyapp\u002F.venv\u002Fbin\u002Fpython manage.py serve \\\n       --  port  =80 \\\n       --static \\\n       --media \\\n       --check-migrations-apply\n   \n   Restart  =always\n   RestartSec  =3\n   StandardOutput  =journal\n   StandardError  =journal\n   LimitNOFILE  =65535\n   \n   [Install]\n   WantedBy  =multi-user.target\n  Enable and start the service:     sudo   systemctl   daemon-reload\n   sudo   systemctl   enable   --now   django.service\n  Inspect service health:     curl   -I   http:\u002F\u002Flocalhost\u002Falive\n   curl   -I   http:\u002F\u002Flocalhost\u002Fready\n   3. Cloud PaaS (Fly.io, AWS ECS, Render)  Modern Cloud application platforms rely on standard HTTP health check probes to verify container status and route traffic. Hurricane's built-in probes integrate naturally with these platforms.  Fly.io Deployment  Fly.io uses   fly.toml  to configure application health checks and HTTP service routing:     app =   \"my-django-app\"\n   primary_region =   \"fra\"\n   \n   [  http_service  ]\n     internal_port =   8000\n     force_https =   true\n     auto_stop_machines =   false\n     auto_start_machines =   true\n     min_machines_running =   1\n   \n     [[  http_service  .  checks  ]]\n       interval =   \"10s\"\n       timeout =   \"2s\"\n       grace_period =   \"5s\"\n       method =   \"GET\"\n       path =   \"\u002Falive\"\n   \n     [[  http_service  .  checks  ]]\n       interval =   \"15s\"\n       timeout =   \"2s\"\n       method =   \"GET\"\n       path =   \"\u002Fready\"\n  In your   Dockerfile , start Hurricane with combined ports:     CMD   [  \"python\"  ,   \"manage.py\"  ,   \"serve\"  ,   \"--port=8000\"  ,   \"--probe-port=8000\"  ,   \"--static\"  ]\n   AWS ECS \u002F Fargate with Application Load Balancer (ALB)  When registering Hurricane containers into an AWS ECS Target Group behind an Application Load Balancer:    Target Port :   8000  (HTTP)   Health Check Path :   \u002Fready   Health Check Interval :   15 seconds   Healthy Threshold :   2   Unhealthy Threshold :   3  During rolling ECS task deployments, the ALB automatically polls   \u002Fready . If database connection pools are not ready or if request queues saturate, Hurricane returns   HTTP 400 , prompting the ALB to route traffic to healthy tasks until the new task is fully ready.   Port Strategy: Combined vs. Isolated Probes  Hurricane supports two probe port modes to match your deployment architecture:     Strategy  Command  Description & Target Environments     Isolated Probe Port (Default)   python manage.py serve --port=8000  (probes on   8001 )   Default behavior.  Probes and Prometheus metrics run on   port + 1  (8001). Ideal for Docker Compose and Kubernetes to prevent user traffic from blocking health probes.    Combined Port   python manage.py serve --port=8000 --probe-port=8000  Probes run integrated directly on port 8000 alongside user traffic. Ideal for PaaS (Fly.io, AWS ECS, Render) requiring single-port routing.  In standalone and Cloud PaaS deployments, running on a single combined port simplifies firewall rules, ingress configurations, and container port mapping while retaining the full benefits of   \u002Falive ,   \u002Fready ,   \u002Fstartup , and   \u002Fmetrics .  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":102,"path":103,"dir":104,"title":105,"description":106,"keywords":107,"body":118},"content:2.configuration:1.settings.md","\u002Fconfiguration\u002Fsettings","configuration","Settings & Parameters","Complete reference of all Django Hurricane configuration parameters, settings, CLI flags, and environment variables.",[108,109,110,111,112,113,114,115,116,117],"Configuration Conventions & Precedence","Server Core Settings","Static & Media File Serving","Fast-404 Security Settings","Rate Limiting Settings","Kubernetes Health Probes & Metrics","Process Lifecycle & Resource Limits","Startup Commands & Migrations","Debugger Settings","Webhooks","  Configuration Reference  Django Hurricane provides a flexible configuration system supporting   Django Settings ,   Command-Line Arguments , and   Environment Variables .   Configuration Conventions & Precedence  Full Symmetry Between Prefixed and Unprefixed Names  Hurricane provides   100% naming symmetry  across all configuration formats:    Django   settings.py : Every setting can be declared using the concise setting name (e.g.   PORT = 8000 ,   RATE_LIMIT = \"10\u002Fs\" ,   FAST_404 = \"auto\" ) or the explicit namespaced equivalent (e.g.   HURRICANE_PORT = 8000 ,   HURRICANE_RATE_LIMIT = \"10\u002Fs\" ). Both forms are evaluated identically.   Environment Variables : Can be specified with   HURRICANE_  (recommended in container environments to avoid name collisions) or without (e.g.   HURRICANE_PORT=8000  or   PORT=8000 ).   Rate Limiting : Rate limiting can be configured directly with individual scalar settings (  RATE_LIMIT ,   RATE_LIMIT_BURST ,   RATE_LIMIT_PROXY_HEADER ,   RATE_LIMIT_ENABLED ) without requiring a nested dictionary. (The dictionary syntax   HURRICANE_RATE_LIMIT = {\"ENABLED\": True, \"RATE\": 10.0, ...}  continues to be supported).   CLI Arguments : Standard command-line flags passed to   python manage.py serve  (e.g.   --port=8000 ).  Precedence Order  When the same parameter is specified in multiple places, Hurricane resolves the final value in this order:    CLI Arguments  (highest priority)   Django   settings.py  (recommended for application configuration)   Environment Variables  (ideal for container runtime overrides)   Server Core Settings  PORT   The TCP port on which the HTTP application server listens for incoming Django traffic.  PROBE_PORT   Dedicated port for Kubernetes health probes (  \u002Falive ,   \u002Fready ,   \u002Fstartup ) and Prometheus metrics (  \u002Fmetrics ). Keeping probe traffic isolated prevents health checks from being starved by heavy application traffic. When omitted, defaults to   port + 1 .  WORKERS   Maximum concurrency ceiling and worker thread pool size used to execute Django code. When omitted, defaults to the number of available CPU cores plus 4.  RUNTIME_THREADS   Number of Rust\u002FTokio async runtime worker threads in Hurricane's underlying   Granian  engine. Defaults to detected container CPUs (capped at 4) to prevent CFS quota throttling in small pods.  RUNTIME_MODE   Async runtime engine architecture in Granian:   'auto' ,   'st'  (single-threaded runtime), or   'mt'  (multi-threaded work-stealing runtime). In   'auto' , defaults to   'st'  if   runtime_threads == 1  (optimal for Kubernetes pods with   ≤ 1  vCPU to eliminate cross-thread synchronization overhead and avoid Linux CFS CPU quota throttling), and   'mt'  when multiple runtime threads are allocated.  AUTORELOAD   Reloads code automatically when Python source file changes are detected. Intended for local development.  DEBUG   Enables verbose debug flag. When enabled, health probe errors return detailed error strings rather than generic status codes.   Static & Media File Serving  STATIC   Enables high-performance static file serving using   STATIC_URL  and   STATIC_ROOT . When   STATIC_ROOT  is populated (e.g. after   collectstatic ), files are served natively in Rust via Granian at Nginx-grade speed (\u003C20µs). In development or when   STATIC_ROOT  is empty, Hurricane automatically falls back to dynamic discovery across   STATICFILES_DIRS  and all installed apps without requiring   collectstatic . For architecture details and workflows, see the   Static & Media Files Guide .  COLLECTSTATIC   Automatically runs Django's   collectstatic  command during server pre-flight startup before the network socket binds. Populates   STATIC_ROOT  so Granian can immediately mount assets into its native Rust streaming engine.  MEDIA   Enables serving user-uploaded media files directly from   MEDIA_ROOT  under   MEDIA_URL . Mounted natively in Granian when the directory exists on disk.  STATIC_WATCH   List of extra directories or file paths to watch for changes during development. When combined with   --autoreload , modifying any watched asset triggers Granian to reload and synchronize static bundles.  STATIC_CACHE_EXPIRES   HTTP   Cache-Control: max-age  header duration in seconds applied to static assets served through Granian's native Rust mount. Defaults to 86400 (24 hours).   Fast-404 Security Settings  FAST_404   Fast-404 protection strategy. Supported values:   auto ,   signature ,   prefix , or   off . In   auto  mode, prefix matching is used when valid URL prefixes can be extracted, automatically falling back to signature matching when a root catch-all or CMS router is detected. For details on how signatures and on-demand caching operate, see the   Signature Mode & Anti-Django Patterns Guide . Setting to   off  or passing   --no-fast-404  disables the shield.  FAST_404_PATTERNS   List of custom regex patterns or file endings to drop at the gateway before reaching Django middleware or database connections. Custom patterns extend the comprehensive   Built-in Signature Pattern Categories  covering PHP\u002FWordPress, Laravel, Java\u002FSpring Actuators, ASP.NET, Node.js, and database dump probes.  FAST_404_EXTRA_PREFIXES   List of additional URL path prefixes to drop immediately at the gateway when running in prefix mode.   Rate Limiting Settings  RATE_LIMIT   Sustained request rate allowed per second per client IP address (e.g.   10\u002Fs ,   20.0 , or   off  \u002F   False  to disable). Can also be configured via dictionary if preferred.  RATE_LIMIT_BURST   Burst token capacity allowed above the sustained rate limit for short traffic bursts.  RATE_LIMIT_PROXY_HEADER   Proxy header used to extract the client IP address behind load balancers or Kubernetes Ingress controllers.  RATE_LIMIT_ENABLED   Explicit boolean switch (  True  or   False ) to toggle the rate limiter without altering rate or burst thresholds.   Kubernetes Health Probes & Metrics  STARTUP_PROBE   URL route on the probe port for Kubernetes startup checks. Returns HTTP 200 once initialization and pre-flight commands have completed.  LIVENESS_PROBE   URL route on the probe port for Kubernetes liveness checks. Verifies that the server process and thread pool are actively responding.  READINESS_PROBE   URL route on the probe port for Kubernetes readiness checks. Verifies database connectivity and pending request backlog.  REQ_QUEUE_LEN   Maximum length of the pending request queue before   \u002Fready  returns HTTP 400 to temporarily shed ingress traffic.  NO_PROBE   Disables the health probe server completely.  METRICS   URL route on the probe port for Prometheus metrics exposition.  NO_METRICS   Disables Prometheus metric collection and exposition.  LOG_PROBES   When   False  (default), HTTP access logging for probe requests (  \u002Falive ,   \u002Fready ,   \u002Fstartup ,   \u002Fmetrics ) is suppressed to prevent log noise. Set to   True  in   settings.py  to log all probe requests.   Process Lifecycle & Resource Limits  MAX_LIFETIME   Maximum number of requests after which a worker process is restarted. When   None , processes run indefinitely.  MAX_MEMORY   Maximum memory (Resident Set Size) in megabytes before process reload. When   None , no memory reload limit is enforced.  MAX_BODY_SIZE   Maximum size of the request body in bytes.  MAX_BUFFER_SIZE   Maximum size of the request buffer in bytes.   Startup Commands & Migrations  COMMAND   Management command to run asynchronously during pod startup before the server opens traffic.  CHECK_MIGRATIONS   Checks if pending database migrations were applied before starting the server.  CHECK_MIGRATIONS_APPLY   Checks if database migrations are pending and applies them automatically prior to opening traffic.   Debugger Settings  DEBUGGER   Opens a debugger port according to the Debug Adapter Protocol (e.g. for VS Code).  DEBUGGER_PORT   The port for the debug client to attach to.  PYCHARM_HOST   Host of the remote PyCharm debug server.  PYCHARM_PORT   Port of the remote PyCharm debug server.   Webhooks  WEBHOOK_URL   Target URL where Hurricane sends asynchronous lifecycle notifications (startup, liveness, graceful termination).  HURRICANE_VERSION   Custom version string included in webhook payloads for deployment tracking.",{"id":120,"path":121,"dir":122,"title":123,"description":124,"keywords":125,"body":131},"content:3.concepts:1.kubernetes-probes.md","\u002Fconcepts\u002Fkubernetes-probes","concepts","Kubernetes Health Probes","Complete architectural breakdown of Startup, Liveness, and Readiness probes in Django Hurricane.",[126,127,128,129,130],"Probe Lifecycle Overview","1. Startup Probe (\u002Fstartup)","2. Readiness Probe (\u002Fready) & Congestion Shedding","3. Liveness Probe (\u002Falive) & Self-Healing","4. Port Isolation with --probe-port","  Kubernetes Health Probes  In Kubernetes, a container that is technically \"running\" (process PID is alive) might actually be deadlocked, running database migrations, or drowning in a request backlog.  Kubernetes relies on three distinct probes to manage container lifecycles:    Startup Probe (  \u002Fstartup ) : \"Has Django finished booting and applying preflight commands?\"   Liveness Probe (  \u002Falive ) : \"Are the application server and worker threads healthy, or are they deadlocked?\"   Readiness Probe (  \u002Fready ) : \"Is the database reachable and does the container have capacity to accept traffic right now?\"   Probe Lifecycle Overview     sequenceDiagram\n       autonumber\n       actor Kubelet\n       participant Hurricane as Hurricane Server\n       participant DB as Database \u002F Checks\n       participant Service as K8s Service Endpoints\n   \n       Note over Kubelet, Hurricane: Phase 1: Container Startup\n       loop Every 2s until 200 OK\n           Kubelet->>Hurricane: GET \u002Fstartup\n           alt Migrations \u002F Commands in progress\n               Hurricane-->>Kubelet: 400 Bad Request (Not finished)\n           else Initialization complete\n               Hurricane-->>Kubelet: 200 OK (Startup complete)\n           end\n       end\n   \n       Note over Kubelet, Service: Phase 2: Traffic Routing & Liveness\n       par Readiness Polling\n           loop Every 2s\n               Kubelet->>Hurricane: GET \u002Fready\n               Hurricane->>DB: Check DB connection & queue backlog\n               alt Queue saturated or DB down\n                   Hurricane-->>Kubelet: 400\u002F500 (Unready)\n                   Kubelet->>Service: Remove Pod IP from Endpoints (Traffic Shedding)\n               else Healthy & capacity available\n                   Hurricane-->>Kubelet: 200 OK (Ready)\n                   Kubelet->>Service: Keep\u002FAdd Pod IP in Endpoints\n               end\n           end\n       and Liveness Polling\n           loop Every 5s\n               Kubelet->>Hurricane: GET \u002Falive\n               alt Worker thread deadlocked \u002F timeout\n                   Hurricane--xKubelet: Probe Timeout \u002F 500\n                   Kubelet->>Hurricane: KILL & RESTART CONTAINER (Self-Healing)\n               else Server responsive\n                   Hurricane-->>Kubelet: 200 OK (Alive)\n               end\n           end\n       end\n   1. Startup Probe (  \u002Fstartup )  The   Startup Probe  prevents Kubernetes from killing slow-starting containers. Without a startup probe, an aggressive liveness probe will kill Django while it is importing large dependencies or running database migrations (the classic   Kubernetes CrashLoopBackOff death spiral ).  How Hurricane Handles Startup:   Returns   HTTP 400 Bad Request  (  Startup is not finished yet ) while preflight tasks are executing:\n   Synchronous management commands (e.g.   --command \"collectstatic --noinput\" ).  Database schema migrations (e.g.   --check-migrations-apply ).  Startup system checks (see the   Developer Guide  for writing custom health checks).  Returns   HTTP 200 OK  the moment Django is ready to serve requests.  While   \u002Fstartup  returns 400, Kubernetes disables the liveness probe and keeps the pod out of service endpoints.   2. Readiness Probe (  \u002Fready ) & Congestion Shedding  The   Readiness Probe  dictates whether Kubernetes routes incoming user traffic to the pod. If a pod reports unready:    Zero Downtime Traffic Shedding:  Kubernetes removes the Pod's IP from the Service endpoints.   No Container Restart:  The container is   NOT  restarted. Existing requests finish cleanly.  Once the pod recovers, Kubernetes immediately restores traffic.     graph TD\n       A[\"Incoming GET \u002Fready\"] --> B{\"Startup Finished?\"}\n       B -- No --> C[\"Return 400 Bad Request\"]\n       B -- Yes --> D{\"Current Backlog >= req_queue_len?\"}\n       D -- Yes --> E[\"Return 400: Queue limit exceeded\"]\n       E --> F[\"K8s pulls Pod from Endpoints\"]\n       D -- No --> G{\"Database & Custom Checks OK?\"}\n       G -- No --> H[\"Return 500: Check Error\"]\n       H --> F\n       G -- Yes --> I[\"Return 200 OK\"]\n       I --> J[\"K8s routes traffic to Pod\"]\n  Real-Time Backlog Tracking:  Under Hurricane, the   --req-queue-len  parameter sets the maximum tolerable request backlog queue before a pod sheds load:   Backlog is tracked via shared memory (  SharedMetrics ).  When all worker threads are occupied and requests begin accumulating,   \u002Fready  responds with   400 Bad Request .  Upstream ingress controllers route traffic to other pods in the replica set instead of overwhelming this instance.   3. Liveness Probe (  \u002Falive ) & Self-Healing  The   Liveness Probe  detects catastrophic failures like Python worker thread deadlocks, infinite loops, or hung C extensions.  How Hurricane Handles Liveness:   Verifies that the server process is responsive and that worker threads can service requests.  When worker threads are deadlocked, requests to   \u002Falive  time out in Kubernetes.  After   failureThreshold  consecutive timeouts (e.g., 2 failures), Kubernetes issues   SIGKILL  to the hung container and spawns a fresh container instance.   4. Port Isolation with   --probe-port  In high-throughput environments, querying health probes on the same port as application traffic is dangerous: slow file uploads or heavy queries can delay probe handling and trigger false timeouts.  Hurricane solves this by allowing cluster probes to run on a dedicated secondary port:     python   manage.py   serve   --port   8000   --probe-port   8001\n     graph LR\n       subgraph Cluster[\"Kubernetes Cluster\"]\n           User[\"External User Traffic\"] -->|Port 8000| App[\"Main Django App Server\"]\n           Kubelet[\"Kubelet Health Monitor\"] -->|Port 8001| Probes[\"Dedicated Probe Server\"]\n       end\n   \n       subgraph Memory[\"Pod Shared Memory\"]\n           App \u003C-->|Atomic Metrics| SHM[(\"POSIX Shared Memory\")]\n           Probes \u003C-->|Real-time Backlog & Health| SHM\n       end\n    Port 8000:  Handles Django application traffic, views, static assets, and media.   Port 8001:  Serves   \u002Fstartup ,   \u002Falive ,   \u002Fready , and   \u002Fmetrics . Probe responses answer in   \u003C 2ms , completely isolated from main thread traffic.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":133,"path":134,"dir":122,"title":135,"description":136,"keywords":137,"body":142},"content:3.concepts:2.rust-engine.md","\u002Fconcepts\u002Frust-engine","Rust-Powered Engine","How Hurricane leverages a high-performance Rust Hyper and Tokio core for zero-copy asynchronous HTTP runtime performance.",[138,139,140,141],"Architecture Overview","Why Rust Over Python Event Loops?","Zero-Config Unified Asynchronous Front-Door","⚡ Comparative Benchmarks: Hurricane 1.x (Tornado) vs. Hurricane 2.0 (Granian Rust Engine)","  Rust-Powered Engine  Hurricane 2.0 replaced Tornado's legacy Python asyncio event loop with a high-performance HTTP engine built directly on Rust’s   Hyper  and   Tokio  runtimes, powered by    Granian .   Architecture Overview     graph TD\n       Client[\"Incoming Client TCP Traffic\"] --> Hyper[\"Rust Hyper HTTP Parser\"]\n       Hyper --> Tokio[\"Tokio Event Loop \u002F Worker Dispatch\"]\n   \n       subgraph RustCore[\"Rust Core (Granian)\"]\n           Hyper\n           Tokio\n       end\n   \n       Tokio -->|Zero-Copy Dispatch| Gateway[\"Hurricane Base Gateway\"]\n   \n       subgraph PythonRuntime[\"Python Runtime\"]\n           Gateway --> Protection{\"Fast-404 & Rate Limiter\"}\n           Protection -- Allowed --> ProtocolSplit{\"Protocol Detection\"}\n           ProtocolSplit -->|WSGI_APPLICATION| WSGI[\"Hurricane Native Rust WSGI Worker\"]\n           ProtocolSplit -->|ASGI_APPLICATION| ASGI[\"Hurricane Native Rust ASGI Worker\"]\n           WSGI --> DjangoWSGI[\"Django Application Stack\"]\n           ASGI --> DjangoASGI[\"Django Async \u002F Channels Stack\"]\n       end\n   Why Rust Over Python Event Loops?  Previous versions of Hurricane used Tornado to bridge asynchronous networking with Django's synchronous WSGI layer. Under high concurrency, Python's single-threaded event loop became a bottleneck:    GIL Contention:  Switching between Python coroutines and worker thread pools incurred high CPU context-switching overhead.   Buffer Saturation:  Large file uploads or request storms flooded Python's memory heap before threads could process them.   Event Loop Starvation:  Blocking C libraries or compute-heavy tasks temporarily froze probe responsiveness.  With Hurricane's Rust Engine (powered by   Granian ):    Rust Handles the Network:  Socket connection management, TLS termination, HTTP 1.1\u002F2 parsing, and keep-alive pools run entirely in compiled Rust without touching Python or the Global Interpreter Lock (GIL).   Native Thread Workers:  For WSGI applications, Hurricane manages OS worker threads directly from Rust via Granian's native worker architecture, invoking the WSGI callable only when a worker thread is free.   Zero-Copy File Streaming:  Static and media files are streamed with minimal memory footprint.   Zero-Config Unified Asynchronous Front-Door  Hurricane runs on a unified Tokio-based asynchronous front-door, automatically auto-detecting your application structure:     graph TD\n       Client[\"Incoming Requests\"] --> RustCore[\"Tokio Reactor: Granian Engine\"]\n       RustCore --> Tier2[\"Hurricane Tier 2 Edge Triage\"]\n       Tier2 -->|Fast-404 \u002F 429 \u002F Probes \u002F Static| InstantExit[\"Sub-Microsecond Direct Response\"]\n       Tier2 -->|Valid Traffic| ConcurrencyGate[\"Async Concurrency Gate: workers\"]\n       ConcurrencyGate --> Check{\"Is ASGI_APPLICATION in settings?\"}\n       Check -- Yes --> NativeASGI[\"Native ASGI Coroutine Execution\"]\n       Check -- No --> FastWSGI[\"Parallel ThreadPool Dispatch: FastWsgiToAsgi\"]\n    Zero Configuration:  Simply run   python manage.py serve . Hurricane boots the high-performance Granian ASGI engine on the network edge.   Async & Channels Projects:  If   ASGI_APPLICATION  is configured, requests run natively as coroutines on the Tokio event loop.   Classic Django Projects:  Traditional synchronous views (  WSGI_APPLICATION ) execute across a fully parallel   ThreadPoolExecutor  via   FastWsgiToAsgi , eliminating   asgiref 's single-thread serialization trap.   ⚡ Comparative Benchmarks: Hurricane 1.x (Tornado) vs. Hurricane 2.0 (Granian Rust Engine)  We pit the classic Tornado-based Hurricane against the new Rust-powered Hurricane 2.0 (using Granian) under identical high-concurrency conditions with Locust:     Metric  Hurricane 1.x (Tornado)  Hurricane 2.0 (Granian Engine) 🦀  Difference     False Readiness Failures (  HTTP 400 )   160 flapping events   0 events   -100.0% (Eliminated!)    Peak Throughput (RPS)  313.3 req\u002Fs   630.9 req\u002Fs   +101.4% (2x faster)    P50 Median Latency  130.0 ms   66.0 ms   -49.2% (Half the wait)    P99 Tail Latency  220.0 ms   120.0 ms   -45.5% faster    Probe Latency Under Load  170.0 ms   94.0 ms   -44.7% faster   Under heavy traffic, Hurricane 1.x mistook pending asyncio task counts for saturated request backlogs, triggering 160 false unready events that pulled pods out of service endpoints. Hurricane 2.0's Granian Rust engine completely eliminates false unready flaps while doubling throughput.    Reproduce & Run Benchmarks   Explore the reproducible benchmark suite, load scenarios, and raw result datasets at    django-hurricane\u002Fdjango-hurricane-bench  on GitHub.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":144,"path":145,"dir":122,"title":146,"description":147,"keywords":148,"body":153},"content:3.concepts:3.fast-404-protection.md","\u002Fconcepts\u002Ffast-404-protection","Fast-404 Protection","First Line of Defense against automated vulnerability scanners, dictionary attacks, and malicious probes.",[149,150,151,152],"How It Works Internally","Signature Mode & Anti-Django Patterns","On-Demand Dynamic Caching Architecture","Architectural Recommendations for 404 Handlers","  Fast-404 Protection  Automated vulnerability scanners continuously assault Django workloads with dictionary attacks probing for PHP scripts, administrative panels, and environment leaks (  \u002F.env ,   \u002Fwp-login.php ,   \u002F.git\u002Fconfig ,   \u002Fxmlrpc.php ).  Under traditional Django setups, every attack request executes your entire middleware stack, runs session queries, and compiles a 404 error template.  Hurricane's   Fast-404 Engine  intercepts malicious and non-existent routes at the outer gateway edge in   sub-microsecond speed , completely bypassing Django's middleware pipeline, database pool, and template rendering engine.   How It Works Internally  1. Decision Flowchart     graph TD\n       Req[\"Incoming HTTP Request\"] --> ProbeCheck{\"Is Cluster Probe?\"}\n       ProbeCheck -- Yes --> ServeProbe[\"Serve Probe Directly\"]\n       ProbeCheck -- No --> CacheCheck{\"In-Memory 404 Cache Hit?\u003Cbr\u002F>Key: host:language:scheme\"}\n       CacheCheck -- Yes --> DropCached[\"INSTANT DROP: Serve Cached 404\u003Cbr\u002F>Latency: &lt; 0.35µs\"]\n       CacheCheck -- No --> SigCheck{\"Matches Anti-Django Signature?\u003Cbr\u002F>.php, .env, wp-*, actuator, etc.\"}\n       SigCheck -- Yes --> DropCold[\"INSTANT DROP: Serve Styled Fallback 404\u003Cbr\u002F>Never touches Django or DB\u003Cbr\u002F>Latency: &lt; 0.35µs\"]\n       SigCheck -- No --> CatchAllCheck{\"Root Catch-All \u002F CMS Mode?\"}\n       CatchAllCheck -- Yes --> ForwardDjango[\"Forward to Django Pipeline\"]\n       CatchAllCheck -- No --> PrefixCheck{\"Top-Level Prefix in Whitelist?\"}\n       PrefixCheck -- No --> ForwardDjangoFirst[\"Forward to Django Once\u003Cbr\u002F>Capture and Cache 404\"]\n       PrefixCheck -- Yes --> ForwardDjango\n   Signature Mode & Anti-Django Patterns  When Hurricane runs in   signature  mode (or in   auto  mode when a root wildcard or CMS routing is detected), it inspects incoming request URLs against a high-performance compiled regular expression targeting   non-Django vulnerabilities, scripts, tools, and frameworks .  Because Django is a Python framework, it will never legitimately host PHP scripts, ASP.NET handler files, Java Spring Actuators, or exposed Node.js metadata. Hurricane drops these probes at Tier 2 in   under 0.35 microseconds , shielding your database connection pool and thread workers from being exhausted by botnets.  Built-in Signature Pattern Categories     Category  Targets & Frameworks  Example Probes Blocked     Non-Python Script & Binary Extensions  PHP, ASP.NET, Java Servlets\u002FJSP, Perl\u002FCGI   .php ,   .asp ,   .aspx ,   .jsp ,   .jspx ,   .cgi ,   .pl ,   .action ,   .do ,   .ashx ,   .asmx ,   .axd ,   .faces ,   .dll ,   .exe    Sensitive Config & Secrets Leaks  Environment, VCS, Cloud & Container configs   \u002F.env* ,   \u002F.git\u002F* ,   \u002F.svn\u002F* ,   \u002F.hg\u002F* ,   \u002F.aws\u002F* ,   \u002F.docker\u002F* ,   \u002F.htaccess ,   \u002F.DS_Store ,   \u002F.bash_history ,   web.config ,   docker-compose.yml ,   database.yml    Database Backups & Dumps  Raw SQL exports and compressed dumps   dump.sql ,   backup.sql.gz ,   database.sql ,   db.sql ,   users.sql    Node.js & Ruby on Rails  Package manifests, lockfiles, Rails consoles   package.json ,   package-lock.json ,   yarn.lock ,   npm-debug.log ,   \u002Frails\u002Finfo\u002F* ,   \u002Frails\u002Fmailers\u002F*    PHP, WordPress & CMS Targets  WordPress core, plugins, REST API, phpMyAdmin   \u002Fwp-admin\u002F* ,   \u002Fwp-content\u002F* ,   \u002Fwp-includes\u002F* ,   \u002Fwp-json\u002Fwp\u002Fv2\u002Fusers ,   \u002Fxmlrpc.php ,   wp-config.php ,   \u002Fwordpress\u002F* ,   \u002Fphpmyadmin\u002F* ,   \u002Fpma\u002F* ,   \u002Fadminer.php    PHP Web Shells & Backdoors  Known exploit shells & discovery scripts   phpinfo.php ,   info.php ,   test.php ,   shell.php ,   c99.php ,   r57.php ,   wso.php ,   alfa.php ,   eval-stdin.php    PHP Framework Exploits  Laravel, Drupal, Joomla, Magento   \u002F_ignition\u002Fexecute-solution ,   \u002F_ignition\u002Fhealth-check ,   \u002Ftelescope\u002F* ,   \u002Fhorizon\u002F* ,   \u002Fcore\u002Finstall.php ,   \u002Fupdate.php ,   \u002Fcron.php ,   \u002Fadministrator\u002Findex.php ,   \u002Fvendor\u002Fphpunit\u002F*    Java & Spring Boot Actuators  Spring Boot Actuator inspection endpoints   \u002Factuator ,   \u002Factuator\u002Fenv ,   \u002Factuator\u002Fheapdump ,   \u002Factuator\u002Fhealth ,   \u002Factuator\u002Fmetrics ,   \u002Factuator\u002Flogfile ,   \u002Factuator\u002Fgateway    Enterprise App Servers & Consoles  Tomcat, JBoss, WebLogic consoles   \u002Fmanager\u002Fhtml ,   \u002Fhost-manager\u002Fhtml ,   \u002Fjmx-console\u002F* ,   \u002Fweb-console\u002F* ,   \u002Finvoker\u002FJMXInvokerServlet    Infrastructure & Search Engines  Search clusters, GIS servers, Exchange   \u002Fsolr\u002Fadmin\u002F* ,   \u002Fgeoserver\u002Fweb\u002F* ,   \u002Fautodiscover\u002F* ,   \u002Fcgi-bin\u002F*  Multilingual & Internationalized (  i18n ) Support  All anti-Django patterns use unanchored path boundaries   (?:^|\u002F) . This guarantees that attacks targeting internationalized Django applications are caught regardless of whether they hit the root URL or a language prefix (e.g.   \u002Fwp-admin\u002F ,   \u002Fde\u002Fwp-admin\u002F ,   \u002Fen\u002F.env , or   \u002Ffr\u002Fxmlrpc.php ).  Zero False Positives for Legitimate Django Endpoints  The pattern definitions strictly avoid intercepting legitimate Django features:    Django Admin (  \u002Fadmin\u002F ) : Fully functional and never blocked.   SSL \u002F ACME Challenges (  \u002F.well-known\u002Facme-challenge\u002F ) : Allowed without interference for automated Let's Encrypt certificate renewals.   SSO & OpenID Discovery (  \u002F.well-known\u002Fopenid-configuration ) : Fully preserved for OAuth \u002F OIDC enterprise authentication.   REST APIs & Static Assets (  \u002Fapi\u002F* ,   \u002Fstatic\u002F* ,   \u002Fmedia\u002F* ) : Allowed cleanly.   On-Demand Dynamic Caching Architecture  Unlike traditional web servers or naive 404 handlers that execute synthetic requests at startup, Hurricane uses a   Lazy Cache-on-First-404  architecture.  Why Synthetic Pre-Rendering is Avoided  Pre-rendering 404 pages during server bootstrap creates fragile race conditions in containerized environments:   Databases might still be running migrations or connection pools may be warming up.  Synthetic   RequestFactory  objects lack live session backends, tenant context, and routing matches (  request.resolver_match ), causing CMS plugins or template tags to raise exceptions.  Multi-site and multilingual setups require different templates per   Host  header and   Accept-Language .  How On-Demand Caching Operates    Zero-Delay Startup (  0ms ) :\nServer boot requires zero database queries and zero template rendering. The gateway initializes instantly with a styled HTML5 fallback response in memory.   First 404 Fallthrough :\nWhen an unknown prefix or legitimate 404 route is hit for the first time:   The request falls through to Django naturally.  Django executes its complete, authentic middleware pipeline and your custom   handler404  view with real database connections, language resolution, site detection, and template engines (such as   Django CMS ,   Wagtail , or   django-sekizai ).  Hurricane’s gateway captures the rendered 404 status, response headers, and HTML body on its way back to the client.   Per-Host & Per-Language Cache Storage :\nHurricane caches the rendered response in an in-memory LRU cache keyed by:     f\"{host}:{language}:{scheme}\"\n     host : Guarantees distinct 404 templates for multi-tenant and multi-site deployments (e.g.   shop.example.com  vs   portal.example.com ).    language : Automatically serves language-specific 404 templates (e.g. German, English, French).    scheme : Preserves protocol-appropriate asset links (  http  vs   https ).   Sub-Microsecond Subsequent Drops :\nOnce cached, any matching route—including automated signature scanner attacks—is served directly from memory in   0.35 microseconds  without consuming thread pool capacity or hitting database pools.   Architectural Recommendations for 404 Handlers  To ensure your custom 404 view runs smoothly with Fast-404 caching:    Use   .filter().first()  for Model Lookups :\nIf your 404 handler fetches settings or site objects based on language (e.g.   PageSetting.objects.get(language_code=language) ), prefer:     page_setting   =   PageSetting.objects.filter(  language_code  =  language).first()   or   PageSetting.objects.first()\n  This prevents unexpected   DoesNotExist  exceptions when scanner requests arrive with unconfigured language codes.   Avoid Auth Redirects in 404 Views :\nDo not wrap global 404 handlers with   @login_required  or redirect invalid paths to   \u002Flogin\u002F . Fast-404 relies on the response having status   404  to populate its cache. Returning a   302  prevents Fast-404 from caching the response.   Let Signature Attacks Drop at the Edge :\nLeave   FAST_404 = \"auto\"  enabled. Malicious bot storms scanning for   .env  or   wp-admin  will be stopped at the outer edge, keeping your Django application resilient under heavy traffic.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":155,"path":156,"dir":122,"title":157,"description":158,"keywords":159,"body":163},"content:3.concepts:4.rate-limiting.md","\u002Fconcepts\u002Frate-limiting","Request Rate Limiting","In-memory token-bucket rate limiting for DoS and flood protection in Django Hurricane.",[160,161,162],"How the Token Bucket Works","Kubernetes Client IP Extraction","Silent Operation Policy","  Request Rate Limiting  Malicious scripts, scrapers, and volumetric Denial-of-Service (DoS) floods can quickly overwhelm Django worker threads and exhaust database connection pools.  Hurricane features a built-in, in-memory   Token Bucket Rate Limiter  enabled by default that enforces traffic quotas at the edge before requests reach Django.   How the Token Bucket Works     graph TD\n       subgraph BucketGroup[\"Token Bucket per Client IP\"]\n           Refill[\"Refill: +10 tokens per second\"] --> Bucket[(\"Capacity: 30 tokens\")]\n       end\n   \n       Req[\"Incoming Request from Client IP\"] --> Check{\"Tokens >= 1?\"}\n       Check -- Yes --> Consume[\"Deduct 1 Token\"]\n       Consume --> Forward[\"Forward Request to Django Pipeline\"]\n       Check -- No --> Reject[\"SILENT REJECT: Return HTTP 429\u003Cbr\u002F>Latency: &lt; 5µs\"]\n  Why Default to 10 req\u002Fs with a Burst of 30?  A naive hard limit of 10 requests\u002Fsecond will break modern web browsers: loading an average Django web page triggers 15 to 25 parallel requests for CSS, JavaScript, fonts, and assets in under 300ms.    Sustained Rate (10 req\u002Fs):  The steady-state consumption speed.   Burst Allowance (30 tokens):  Allows legitimate browser page-load storms, tab refreshes, and corporate office NATs without triggering false positives.  If a flood bot fires 100 requests in 1 second, the first 30 succeed and the remaining 70 are dropped instantly with   429 Too Many Requests .   Kubernetes Client IP Extraction  In Kubernetes, traffic routes through cloud load balancers and ingress controllers. If a web server inspects the raw TCP socket address (  REMOTE_ADDR ), every request appears to originate from the internal Ingress Pod IP, locking out all users globally within seconds.  Hurricane safely resolves the real client IP using trusted forwarding headers:     X-Forwarded-For :  Extracts the leftmost non-proxy IP from comma-separated proxy chains:\n     X-Forwarded-For: 203.0.113.195, 10.42.0.1, 10.42.0.15\n                    └─ Client IP ──┘\n    X-Real-IP :  Fallback if   X-Forwarded-For  is missing.    REMOTE_ADDR :  Final fallback for local development.   Silent Operation Policy  During a flood attack, writing access logs for thousands of dropped requests creates a secondary Denial-of-Service on disk I\u002FO, stdout buffers, and log forwarders (Promtail, Fluentbit).  Hurricane enforces a strict   Silent Drop Policy :    Startup Audit Log:  Prints exactly one structured configuration log on boot:\n     2026-10-21 12:00:00 INFO hurricane.server.limiter Rate limiter active: 10.0 req\u002Fs (burst: 30) [IP Header: X-Forwarded-For]\n   Zero Log Pollution:  Requests dropped with   429 Too Many Requests  produce   zero log lines .   Probe Exemption:  Kubernetes cluster probes (  \u002Falive ,   \u002Fready ,   \u002Fstartup ,   \u002Fmetrics ) are checked   before  rate limits and are   never throttled .  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":165,"path":166,"dir":122,"title":167,"description":168,"keywords":169,"body":172},"content:3.concepts:5.shared-memory-metrics.md","\u002Fconcepts\u002Fshared-memory-metrics","Shared Memory & Prometheus Metrics","Architecture of Hurricane's cross-process POSIX shared memory metrics and Prometheus scraping.",[170,171],"Binary Buffer Memory Layout","Prometheus Exposition (\u002Fmetrics)","  Shared Memory & Prometheus Metrics  When running multi-process application servers (e.g. separate probe servers on port 8001 or multiple worker threads), tracking real-time metrics across process boundaries without database locking or inter-process communication (IPC) bottlenecks is a difficult challenge.  Hurricane solves this by allocating an atomic   POSIX Shared Memory Buffer  (  SharedMetrics ) directly in the OS virtual memory space.   Binary Buffer Memory Layout  Hurricane maps a 72-byte fixed-size binary buffer in shared memory (  \u002Fdev\u002Fshm ):     classDiagram\n       class SharedMemoryBuffer {\n           +Bytes 00-08: uint64 requests_count\n           +Bytes 08-16: double response_time_sum\n           +Bytes 16-24: uint64 response_time_count\n           +Bytes 24-32: double startup_time\n           +Bytes 32-40: int64 queue_length (backlog)\n           +Bytes 40-48: int64 health (liveness state)\n           +Bytes 48-56: int64 readiness (readiness state)\n           +Bytes 56-64: int64 active_requests\n       }\n  Why Shared Memory?    Sub-Microsecond Latency:  Reading and updating counters uses direct memory pointers (  struct.pack_into  and   struct.unpack_from ).   Zero IPC Latency:  The probe server on port 8001 can check the worker backlog on port 8000 in   \u003C 1 microsecond  without opening sockets or making RPC calls.   No Garbage Collection Pressure:  Fixed-size binary struct allocations produce 0 Python object garbage.   Prometheus Exposition (  \u002Fmetrics )  Hurricane includes a native Prometheus exporter available on the   \u002Fmetrics  endpoint (or on the probe port if separated):  Default Exposed Metrics:     request_counter :  Monotonically increasing counter of all requests received.    response_time_average :  Real-time exponential moving average response time.    request_queue_length :  Current worker backlog queue depth.   Python Runtime Metrics:  Garbage collection collections (  python_gc_objects_collected_total ), process virtual memory, CPU times, and open file descriptors.  Custom Metrics Registry:  Developers can register application-specific custom metrics using Hurricane's metric classes:     CounterMetric : Incrementing event counters.    CalculatedMetric : Dynamically computed gauge values evaluated at scrape time.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":174,"path":175,"dir":122,"title":176,"description":177,"keywords":178,"body":181},"content:3.concepts:6.webhooks.md","\u002Fconcepts\u002Fwebhooks","Lifecycle Webhooks","Asynchronous HTTP notifications for pod lifecycle state changes and health transitions.",[179,180],"Webhook Trigger Flow","Built-in Webhook Types","  Lifecycle Webhooks  In enterprise Kubernetes environments, notifying external observability platforms, incident response systems, or deployment pipelines when a pod changes health state is essential for fast recovery.  Hurricane includes an asynchronous   Webhook Dispatcher  that triggers HTTP notifications when probe states transition.   Webhook Trigger Flow     sequenceDiagram\n       participant Check as Health \u002F System Check\n       participant Metric as Hurricane Metric State\n       participant Webhook as Webhook Dispatcher\n       participant Target as External Webhook Receiver\n   \n       Check->>Metric: Update Status (e.g. Failure detected)\n       alt State has changed\n           Metric->>Webhook: Trigger Webhook (Status = FAILED)\n           Webhook->>Target: POST \u002Fwebhook-url {status, code, timestamp}\n           Target-->>Webhook: 200 OK\n       else State unchanged\n           Note over Metric, Webhook: No webhook fired (deduplicated)\n       end\n   Built-in Webhook Types  Hurricane defines three standard webhook dispatchers corresponding to Kubernetes probe states:     StartupWebhook : Dispatched once preflight management commands and migrations finish.    LivenessWebhook : Dispatched if worker threads deadlock or recover.    ReadinessWebhook : Dispatched when a pod transitions between ready and unready (e.g. database down, congestion limit exceeded).  Payload Structure:  When triggered, Hurricane sends an HTTP POST with a structured JSON body:     {\n     \"code\"  :   \"readiness\"  ,\n     \"status\"  :   \"failed\"  ,\n     \"timestamp\"  :   1792575000  ,\n     \"data\"  : {\n       \"reason\"  :   \"Request queue limit exceeded\"\n     }\n   }\n  Configuration:  Enable webhook dispatching by specifying   --webhook-url  or setting   HURRICANE_WEBHOOK_URL :     python   manage.py   serve   --webhook-url=https:\u002F\u002Falerts.mycompany.com\u002Fk8s\u002Fhooks\u002F\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":183,"path":184,"dir":122,"title":185,"description":186,"keywords":187,"body":192},"content:3.concepts:7.asgi-vs-wsgi.md","\u002Fconcepts\u002Fasgi-vs-wsgi","Unified Asynchronous Front-Door Architecture","Understand Hurricane's three-tier architecture, Tokio edge shields, and how ASGI and WSGI workloads execute under Granian.",[188,189,190,191],"Architectural Comparison","The Three-Tier Pipeline","Readiness Probing: Accurate Soft-Limit Shedding","Common ASGI Pitfalls in Django","  Unified Asynchronous Front-Door Architecture  Django Hurricane executes all traffic through a   Unified Asynchronous Front-Door  powered by    Granian  and Rust's   Tokio  runtime.  Rather than forcing developers to configure fragile transport switches, Hurricane automatically provides high-performance edge shielding on the network perimeter and auto-dispatches to your Django application whether it is written with asynchronous views (  asgi.py ) or traditional synchronous views (  wsgi.py ).   Architectural Comparison     Feature  Synchronous Workloads (  wsgi.py )  Native Asynchronous (  asgi.py )     Intake Reactor  Tokio event loop (Rust Hyper)  Tokio event loop (Rust Hyper)    Edge Triage (Tier 2)  Sub-microsecond (Fast-404, 429, Probes)  Sub-microsecond (Fast-404, 429, Probes)    Execution Dispatch  Parallel   ThreadPoolExecutor  (  FastWsgiToAsgi )  Native async coroutines on Tokio loop    WebSockets & SSE  Handled via sync views or Channels  ✅ Native support    ORM Query Handling  Multi-threaded parallel DB connections  Async ORM (  .aget() ,   .acount() )    Readiness Probing  Concurrency Gate Backlog (  --req-queue-len )  Event Loop Lag Tracking + Backlog   The Three-Tier Pipeline  Hurricane organizes request processing into three distinct tiers:     graph TD\n       Client[\"Incoming Client Requests\"] --> Tier1[\"Tier 1: Tokio Reactor - Granian Rust Engine\"]\n       \n       subgraph Tier2[\"Tier 2: Sub-Microsecond Edge Triage\"]\n           Tier1 --> EdgeFilters{\"Match Edge Rule?\"}\n           EdgeFilters -->|\u002Fready or \u002Falive| ProbeResp[\"Instant Probe Response: ~200µs\"]\n           EdgeFilters -->|Fast-404 Scanner| Drop404[\"Drop Request: ~350ns\"]\n           EdgeFilters -->|Rate Limited| Drop429[\"Reject 429: ~560ns\"]\n           EdgeFilters -->|Static \u002F Media| FileStream[\"Asynchronous Disk Stream\"]\n       end\n   \n       subgraph Tier3[\"Tier 3: Managed Concurrency Gate\"]\n           EdgeFilters -->|Valid Traffic| Gate[\"Async Concurrency Gate: workers\"]\n           Gate --> AppCheck{\"Is ASGI_APPLICATION configured?\"}\n           AppCheck -- Yes --> NativeASGI[\"Native ASGI Coroutine Execution\"]\n           AppCheck -- No --> ThreadPool[\"FastWsgiToAsgi: Parallel ThreadPool\"]\n           ThreadPool --> DjangoWSGI[\"Django Sync Views & ORM\"]\n       end\n  Tier 1: Tokio Non-Blocking Reactor  Granian's compiled Rust core accepts thousands of incoming TCP sockets non-blockingly, parsing HTTP headers and delegating requests to Python coroutines without consuming OS threads.  Tier 2: Sub-Microsecond Edge Triage  Before any request touches Django middleware, view routing, or database connection pools:    Fast-404 Shield:  Intercepts automated scanner attacks (e.g.   \u002F.env ,   \u002Fwp-login.php ) in   ~0.35 µs .   Token-Bucket Rate Limiter:  Evaluates client IP quotas and sheds floods in   ~0.56 µs .   Kubernetes Probes:  Answers   \u002Fready ,   \u002Falive , and   \u002Fmetrics  in microseconds.   Static & Media Files:  Streamed directly from disk without blocking application threads.  Scanners, bots, and probes exit immediately without touching worker threads or database pools.  Tier 3: Managed Concurrency Gate  Legitimate application traffic passes into an asynchronous concurrency gate (  AsyncConcurrencyGate ) sized to your   --workers  limit:    Native ASGI:  Views defined with   async def  run directly as coroutines on the Tokio event loop.   Synchronous WSGI:  Traditional views are dispatched to a multi-threaded   ThreadPoolExecutor  using Hurricane's custom   FastWsgiToAsgi  adapter. Unlike Django's default   asgiref  (which serializes queries to a single thread),   FastWsgiToAsgi  runs queries across multiple worker threads in parallel.   Readiness Probing: Accurate Soft-Limit Shedding  In pure WSGI servers, request backlogs are hidden inside operating system socket buffers, making it impossible to detect application overload accurately.  With Hurricane's Unified Asynchronous Front-Door:    Backlog Tracking (  --req-queue-len ):  Hurricane monitors the exact count of legitimate requests waiting in Tier 3 for a worker slot. If waiting requests exceed   --req-queue-len  (default:   workers * 2 ),   \u002Fready  immediately returns   HTTP 400 Bad Request .   Load Shedding without Drops:  When   \u002Fready  returns 400, Kubernetes Ingress ceases routing new users to this pod. The requests already in the queue are completed normally by worker threads without connection resets. Once the queue drains,   \u002Fready  returns 200 OK.   Event Loop Lag Tracking:  For native async workloads, Hurricane also monitors scheduling responsiveness. If CPU-bound tasks starve the event loop beyond   HURRICANE_LOOP_LAG_THRESHOLD  (default: 200ms),   \u002Fready  sheds traffic.  Benchmark Insights & Architecture Recommendations  Performance evaluations from our benchmark suite at    django-hurricane\u002Fdjango-hurricane-bench  reveal distinct operational trade-offs between modes:    WSGI Concurrency Sizing:  In WSGI mode, response times stack when user concurrency exceeds the available   blocking_threads  count because requests must wait in the socket queue. For synchronous Django workloads, size   --workers  to match your container's CPU quota plus expected concurrent I\u002FO waits.   ASGI High-Throughput Scaling:  Under heavy concurrency (80+ users), Hurricane's ASGI multi-core Tokio runtime achieves   630+ RPS  with sub-100ms P50 latency and   zero false-unready probe flaps , outperforming classic Python asyncio servers by over 100%.   Recommendation:  If your workload is primarily synchronous ORM queries, stick with WSGI for simplicity and raw single-thread speed. If you have async views, WebSockets, or outbound microservice calls, Hurricane's ASGI mode leverages the multi-core Tokio scheduler to maximize throughput without thread exhaustion.   📊   Explore the Data:  Review reproducible load scenarios, Locust scripts, and raw JSON benchmarks at    django-hurricane-bench  on GitHub.   Common ASGI Pitfalls in Django  1. Synchronous ORM Calls in Async Views  Calling synchronous ORM queries directly inside an   async def  view triggers Django's   SynchronousOnlyOperation  exception:     async   def   my_view  (request):\n       # Raises SynchronousOnlyOperation!\n       users   =   User.objects.all()\n       return   JsonResponse({  \"count\"  : users.count()})\n   Correct Approach:  Wrap synchronous calls with   sync_to_async  or use Django's native asynchronous querysets:     async   def   my_view  (request):\n       # Using async iteration or sync_to_async\n       users_count   =   await   User.objects.acount()\n       return   JsonResponse({  \"count\"  : users_count})\n  2. Database Connection Pooling Across Coroutines  In synchronous WSGI, database connections are managed per thread (  django.db.connection ). In ASGI, multiple coroutines interleaving on the same thread cannot share the same synchronous database connection without synchronization. Always rely on Django's asynchronous ORM interfaces (  .aget() ,   .acount() ,   .aexists() ) or explicitly wrap blocks with   sync_to_async(..., thread_sensitive=True) .  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":194,"path":195,"dir":122,"title":196,"description":197,"keywords":198,"body":202},"content:3.concepts:8.django-kubernetes-vs-gunicorn.md","\u002Fconcepts\u002Fdjango-kubernetes-vs-gunicorn","Django on Kubernetes: Hurricane vs. Gunicorn & uWSGI","An architectural comparison of running Django on Kubernetes using Hurricane versus legacy application servers like Gunicorn and uWSGI.",[199,200,201],"Architectural Comparison Matrix","Why Gunicorn Creates Friction in Kubernetes","Migration Blueprint: Switching from Gunicorn to Hurricane","  Django on Kubernetes: Hurricane vs. Gunicorn & uWSGI  When deploying Django into a modern Kubernetes cluster, selecting the right application server dictates cluster stability, memory utilization, and zero-downtime rolling update performance.  Traditional Python application servers like   Gunicorn  and   uWSGI  were designed over a decade ago for long-lived, multi-tenant virtual machines. While battle-tested on static servers, their multi-process master\u002Fworker architecture creates severe architectural friction when containerized inside ephemeral Kubernetes Pods.   Django Hurricane  was designed from the ground up as a   Kubernetes-native application server , replacing legacy Python event loops and process forkers with a high-performance   Rust Hyper\u002FTokio core  (powered by    Granian ) and native Kubernetes lifecycle integrations.   Architectural Comparison Matrix     Feature  Gunicorn + Uvicorn Worker  uWSGI  Django Hurricane (v2.0)     Underlying HTTP Engine  Python socket loop (  asyncio \u002F  sync )  C core with custom protocol   Rust Hyper & Tokio (  Granian )  🦀    Container Concurrency Model  Multi-process fork model (heavy RAM tax)  Multi-process master with preforking   High-density Rust threads with low memory footprint    Kubernetes Health Probes  Requires custom Django views or curl exec  Custom stats server \u002F external scripts   Built-in   \u002Fstartup ,   \u002Falive ,   \u002Fready  out of the box    Traffic Shedding Under Load  Requests queue in OS socket until timeout  Listen queue overflow \u002F dropped packets   Shared memory queue tracking;   \u002Fready  returns 400    Database Migration Sync  Requires manual   initContainers  or Helm hooks  Requires custom bash entrypoint wrapper   Built-in   --check-migrations-apply  before   \u002Fstartup    Edge Bot & Scanner Shield  Hits Django view layer; requires Nginx sidecar  Requires complex regex rewrite rules   Built-in Fast-404 (\u003C50µs drop, zero log spam)    DoS & Flood Rate Limiting  Requires Redis middleware or external WAF  uWSGI internal cache limiter   Built-in Token-Bucket Rate Limiter with proxy headers    Prometheus Metrics  Requires   django-prometheus  polluting URLs  Requires   uwsgi-exporter  sidecar container   Built-in   \u002Fmetrics  endpoint with shared memory metrics   Why Gunicorn Creates Friction in Kubernetes  1. Memory Multiplication vs. Cost-Effective Concurrency  Gunicorn's traditional multi-process model forks   2 * CPUs + 1  independent OS processes:    Duplicated Memory Tax:  Every forked Gunicorn process duplicates Python's runtime, Django models, templates, and imports in RAM. To achieve high concurrency, teams must either pay for expensive, oversized cloud nodes or risk container OOM kills (  SIGKILL , exit code 137) when memory limits are reached.   The Hurricane Advantage:  Hurricane executes on a unified Rust core (powered by   Granian ) with native thread-level parallelism (  blocking_threads  and   runtime_threads ). You achieve high multi-worker concurrency and maximum request density inside each Pod without the heavy RAM multiplication of forked Python processes, dramatically reducing cloud compute costs while maintaining predictable memory limits.   2. Lack of Native Kubernetes Probe Coordination  In Kubernetes, health checks cannot merely verify if a web server process is alive:    Startup Latency:  Heavy Django applications require time to load models, compile templates, and initialize caches. With Gunicorn, developers often rely on simple HTTP ping views; if the database is temporarily slow, the liveness probe kills the container before it finishes booting.   Congestion Visibility:  When Gunicorn's worker threads are all blocked on slow queries, additional requests pile up in the OS socket backlog. Kubelet continues routing ingress traffic to the overwhelmed pod because the   \u002Fping  view might still squeak through or fail unpredictably.   The Hurricane Solution:  Hurricane implements all three native Kubernetes probes:\n    \u002Fstartup : Only reports   200 OK  once preflight database migrations and cache checks succeed.   \u002Falive : Liveness probe that detects deadlocked worker threads and triggers automated container restarts.   \u002Fready : Monitors queue backlog in POSIX shared memory. If the worker queue is congested, it immediately returns   400 Bad Request , signaling   kube-proxy  to shed ingress traffic to sibling pods without killing the container.   3. Eliminating the Ingress \u002F Nginx Sidecar Requirement  Traditional Django Gunicorn deployments often require injecting an   Nginx sidecar container  inside the Pod to handle:   Static and media file serving.  Blocking bot scanners (  .php ,   \u002F.env ,   \u002Fwp-admin\u002F ).  Enforcing rate limits to prevent denial-of-service.   The Hurricane Solution: \nHurricane embeds these capabilities directly into its gateway:    Fast-404 Security Shield:  Intercepts dictionary attacks at the socket layer in microseconds, protecting Django middleware and database connection pools from being exhausted by botnets.   Token-Bucket Rate Limiter:  Operates silently in-memory with automatic   X-Forwarded-For  and   CF-Connecting-IP  resolution.   Static & Media Asset Delivery:  Serves collected assets directly from disk without requiring an auxiliary Nginx container.   Migration Blueprint: Switching from Gunicorn to Hurricane  Migrating an existing Kubernetes Deployment from Gunicorn to Hurricane requires zero changes to your Django views or routing.  Step 1: Install Hurricane  Add   django-hurricane  to your project dependencies:     uv   add   django-hurricane\n   # or\n   pip   install   django-hurricane\n  In   settings.py :     INSTALLED_APPS   =   [\n       # ...\n       \"hurricane\"  ,\n   ]\n  Step 2: Update Kubernetes Container Command   Old (Gunicorn):     command  :\n   -   \"gunicorn\"\n   -   \"myproject.wsgi:application\"\n   -   \"--bind=0.0.0.0:8000\"\n   -   \"--workers=4\"\n   -   \"--timeout=60\"\n   New (Hurricane):     command  :\n   -   \"python\"\n   -   \"manage.py\"\n   -   \"serve\"\n   -   \"--port=8000\"\n   -   \"--probe-port=8001\"\n   -   \"--check-migrations-apply\"\n   -   \"--req-queue-len=15\"\n  Configure your Kubernetes probes to target port   8001  with   \u002Fstartup ,   \u002Falive , and   \u002Fready , and your cluster gains instant zero-config resilience!  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":204,"path":205,"dir":206,"title":207,"description":208,"keywords":209,"body":216},"content:4.performance:1.benchmark-suite.md","\u002Fperformance\u002Fbenchmark-suite","performance","Benchmark Suite Overview","Architecture, methodologies, and empirical performance results from the official Django Hurricane Benchmark Suite evaluating WSGI and ASGI deployments.",[138,210,211,212,213,214,215],"The 6 Evaluated Deployment Paradigms","Workload Routes","Aggregate Performance Metrics (Mixed Workload)","Concurrency Scaling Penalty","Isolated Workload Performance","Reproducing the Benchmarks Locally","  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:     graph TD\n       Locust[Locust Load Runner\u003Cbr\u002F>Headless Step-Load Testing] --> W1[Flavors 1 &amp; 2: WSGI\u003Cbr\u002F>Hurricane WSGI Mode\u003Cbr\u002F>Single vs Auto-Threads\u003Cbr\u002F>Sync DB Connection Pool]\n       Locust --> W2[Flavor 3: ASGI-Sync\u003Cbr\u002F>Hurricane ASGI Mode\u003Cbr\u002F>Django sync_to_async\u003Cbr\u002F>Sync HTTP Requests]\n       Locust --> W3[Flavors 4, 5 &amp; 6: ASGI\u003Cbr\u002F>Hurricane ASGI Mode\u003Cbr\u002F>Clean Async Views with httpx\u003Cbr\u002F>Single vs Auto vs DAB Async ORM]\n       W1 --> DB[(PostgreSQL 17 Database\u003Cbr\u002F>Real Database Storage)]\n       W2 --> DB\n       W3 --> DB\n   The 6 Evaluated Deployment Paradigms  The suite compares six distinct deployment paradigms across Hurricane's runtime engines:    WSGI (Worker=1 \u002F Single Thread) : Hurricane WSGI mode with   --workers 1  (strict single-threaded baseline for 1-to-1 comparison with single-process event loop).   WSGI (Auto Threads \u002F Multi-Thread) : Hurricane WSGI mode with auto-threads calculation   min(32, cpu_count + 4)  threads (traditional production multi-threaded WSGI deployment).   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.   ASGI (Clean Async \u002F Single Thread) : Hurricane ASGI mode with clean async views (  async def ), pooled   httpx  async HTTP client, and   --workers 1 .   ASGI (Auto Threads \u002F 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.   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:     Route  Feature Area  Concurrency Characteristic     POST \u002Fapi\u002Fauth\u002Flogin  Session & Auth Middleware  Cookie signing, session read\u002Fwrite, user credentials validation.    GET \u002Fapi\u002Fauth\u002Fme  Session Verification  Native async session verification (  auser  under ASGI).    GET \u002Fcatalog\u002Frender  Complex Template Rendering  Django Template Language (DTL) overhead, nested loops, filters, context processors.    GET \u002Fapi\u002Fitems  &   POST \u002Fapi\u002Fitems  JSON API Serialization  JSON parsing, model validation, and bulk ORM queries.    GET \u002Fexternal\u002Ffetch  Unreliable Upstream API  Interacts with a mock upstream API (  fake-api  with randomized latency) simulating third-party network delays.    GET \u002Fcatalog\u002Fsearch  Database Queries & Aggregations  Filtering, foreign key joins (  select_related ), and statistical aggregations on PostgreSQL 17.    GET \u002Fapi\u002Fgateway\u002Faggregate  Scatter-Gather Microservices API Gateway  Fan-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:     Flavor  Server Runtime  Throughput  Median (p50)  95th (p95)  99th (p99)  Error Rate  Total Requests     WSGI (Worker=Auto \u002F Multi-Thread)  Hurricane WSGI   147.3 req\u002Fs   230.0 ms   510.0 ms   570.0 ms  0.0%  2,217    ASGI (Forced Sync Views)  Hurricane ASGI   71.5 req\u002Fs   280.0 ms   1900.0 ms   2000.0 ms  0.0%  1,073    ASGI (Worker=Auto \u002F Clean Async)  Hurricane ASGI   60.6 req\u002Fs   300.0 ms   2300.0 ms   2600.0 ms  0.0%  910    ASGI (Worker=1 \u002F Clean Async)  Hurricane ASGI   60.1 req\u002Fs   350.0 ms   2200.0 ms   2500.0 ms  0.0%  901    ASGI + django-async-backend  Hurricane ASGI   59.8 req\u002Fs   720.0 ms   1800.0 ms   2700.0 ms  0.0%  898    WSGI (Worker=1 \u002F Single Thread)  Hurricane WSGI   29.1 req\u002Fs   1300.0 ms   3000.0 ms   3100.0 ms  0.0%  435     Throughput (Requests per Second - Higher is better)\n   WSGI (Worker=Auto \u002F Multi-Thread) [████████████████████████████████]    147.3 req\u002Fs\n   ASGI (Forced Sync Views)         [████████████████                ]     71.5 req\u002Fs\n   ASGI (Worker=Auto \u002F Clean Async) [█████████████                   ]     60.6 req\u002Fs\n   ASGI (Worker=1 \u002F Clean Async)    [█████████████                   ]     60.1 req\u002Fs\n   ASGI + django-async-backend      [█████████████                   ]     59.8 req\u002Fs\n   WSGI (Worker=1 \u002F Single Thread)  [██████                          ]     29.1 req\u002Fs\n     95th Percentile Latency (Lower is better)\n   WSGI (Worker=Auto \u002F Multi-Thread) [█████                           ]    510.0 ms\n   ASGI + django-async-backend      [███████████████████             ]   1800.0 ms\n   ASGI (Forced Sync Views)         [████████████████████            ]   1900.0 ms\n   ASGI (Worker=1 \u002F Clean Async)    [███████████████████████         ]   2200.0 ms\n   ASGI (Worker=Auto \u002F Clean Async) [█████████████████████████       ]   2300.0 ms\n   WSGI (Worker=1 \u002F Single Thread)  [████████████████████████████████]   3000.0 ms\n   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:     Flavor  Initial Load (~12 Users) p50 \u002F p95  Mid Load (~50 Users) p50 \u002F p95  Peak Load (100 Users) p50 \u002F p95  Latency Scaling Penalty     WSGI (Worker=Auto \u002F Multi-Thread)  60.0 ms \u002F 130.0 ms  73.0 ms \u002F 240.0 ms  207.5 ms \u002F 465.0 ms   3.58x    WSGI (Worker=1 \u002F Single Thread)  240.0 ms \u002F 510.0 ms  880.0 ms \u002F 1200.0 ms  1250.0 ms \u002F 2650.0 ms   5.20x    ASGI (Forced Sync Views)  110.0 ms \u002F 240.0 ms  180.0 ms \u002F 420.0 ms  267.5 ms \u002F 1600.0 ms   6.67x    ASGI (Worker=1 \u002F Clean Async)  99.0 ms \u002F 260.0 ms  240.0 ms \u002F 530.0 ms  330.0 ms \u002F 1900.0 ms   7.31x    ASGI + django-async-backend  92.0 ms \u002F 200.0 ms  210.0 ms \u002F 770.0 ms  667.5 ms \u002F 1575.0 ms   7.88x    ASGI (Worker=Auto \u002F Clean Async)  120.0 ms \u002F 230.0 ms  230.0 ms \u002F 510.0 ms  290.0 ms \u002F 1925.0 ms   8.37x   Isolated Workload Performance  When endpoints are benchmarked in isolation without cross-traffic contention, the architectural strengths of each paradigm become distinct:  API Gateway \u002F BFF (Scatter-Gather Fan-Out)     Flavor  Throughput  Median (p50)  95th (p95)  Error Rate     WSGI (Worker=Auto \u002F Multi-Thread)   100.8 req\u002Fs  410.0 ms  840.0 ms  0.0%    ASGI (Forced Sync Views)   87.1 req\u002Fs  390.0 ms  1100.0 ms  0.0%    ASGI (Worker=Auto \u002F Clean Async)   47.1 req\u002Fs  770.0 ms  2300.0 ms  0.0%    ASGI (Worker=1 \u002F Clean Async)   46.7 req\u002Fs  730.0 ms  2600.0 ms  0.0%    ASGI + django-async-backend   39.4 req\u002Fs  950.0 ms  2900.0 ms  0.0%    WSGI (Worker=1 \u002F Single Thread)   12.5 req\u002Fs  2800.0 ms  5600.0 ms  0.0%  External Fetch (Upstream API I\u002FO)     Flavor  Throughput  Median (p50)  95th (p95)  Error Rate     WSGI (Worker=Auto \u002F Multi-Thread)   175.6 req\u002Fs  150.0 ms  360.0 ms  0.0%    ASGI (Forced Sync Views)   107.4 req\u002Fs  330.0 ms  830.0 ms  0.0%    ASGI + django-async-backend   74.6 req\u002Fs  570.0 ms  1500.0 ms  0.0%    ASGI (Worker=1 \u002F Clean Async)   73.1 req\u002Fs  500.0 ms  1700.0 ms  0.0%    ASGI (Worker=Auto \u002F Clean Async)   72.1 req\u002Fs  480.0 ms  1500.0 ms  0.0%    WSGI (Worker=1 \u002F Single Thread)   22.9 req\u002Fs  1600.0 ms  3500.0 ms  0.0%  Catalog Search (PostgreSQL Joins & Aggregates)     Flavor  Throughput  Median (p50)  95th (p95)  Error Rate     WSGI (Worker=Auto \u002F Multi-Thread)   153.1 req\u002Fs  200.0 ms  500.0 ms  0.0%    ASGI + django-async-backend   90.2 req\u002Fs  520.0 ms  880.0 ms  0.0%    WSGI (Worker=1 \u002F Single Thread)   89.0 req\u002Fs  520.0 ms  990.0 ms  0.0%    ASGI (Forced Sync Views)   73.7 req\u002Fs  630.0 ms  1300.0 ms  0.0%    ASGI (Worker=Auto \u002F Clean Async)   70.0 req\u002Fs  670.0 ms  1400.0 ms  0.0%    ASGI (Worker=1 \u002F Clean Async)   69.3 req\u002Fs  650.0 ms  1400.0 ms  0.0%   Reproducing the Benchmarks Locally  Clone the repository and run the automated execution suite:     git   clone   https:\u002F\u002Fgithub.com\u002Fdjango-hurricane\u002Fdjango-hurricane-bench.git\n   cd   django-hurricane-bench\n   \n   # Run full sequential benchmark across all 6 flavors:\n   .\u002Fscripts\u002Frun_benchmark.sh\n   \n   # Target a specific Hurricane version and concurrency parameters:\n   HURRICANE_VERSION  =  2.0.0rc6   BENCH_USERS  =  150   BENCH_DURATION  =  45s   .\u002Fscripts\u002Frun_benchmark.sh\n  For continuous testing, the suite also runs in GitHub Actions via   workflow_dispatch , automatically archiving reports under   archive\u002F  upon completion.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":218,"path":219,"dir":206,"title":220,"description":221,"keywords":222,"body":228},"content:4.performance:2.kubernetes-scaling-findings.md","\u002Fperformance\u002Fkubernetes-scaling-findings","Kubernetes Scaling & Pod Constraints","Empirical findings and architectural implications of running Django Hurricane inside constrained Kubernetes Pods (1-2 vCPUs), probe flapping prevention, and HPA strategies.",[223,224,225,226,227],"1. The Small Pod Constraint (1–2 vCPUs) & Thread Starvation","2. The ASGI Socket Multiplexing Advantage in Small Pods","3. Preventing Kubernetes Health Probe Flapping Under Load","4. Horizontal Pod Autoscaling (HPA) Strategies","5. Cost Optimization: Hurricane vs. Gunicorn Memory Tax","  Kubernetes Scaling & Pod Constraints  Benchmark results from the    Django Hurricane Benchmark Suite  reveal that server architecture decisions that look great on bare-metal hardware behave fundamentally differently inside containerized   Kubernetes Pods .  In cloud-native environments, microservices typically run in lightweight, horizontally autoscaled pods with strict resource quotas (e.g.   1–2 vCPUs ,   1Gi–2Gi  RAM). Understanding how thread limits, socket multiplexing, and probe health interact under these constraints is critical for production resilience.   1. The Small Pod Constraint (1–2 vCPUs) & Thread Starvation  The Bare-Metal Illusion  On an 8- to 16-core dedicated bare-metal server, Hurricane's auto-thread calculation   min(32, CPU + 4)  provisions   12 to 20 worker threads . This abundant threadpool depth easily masks blocking I\u002FO delays; if 4 requests block on an external API or database lock, 16 threads remain available to service incoming traffic.  The Cloud-Native Container Reality  In modern Kubernetes clusters, standard best practices dictate running smaller, horizontally scalable Pods (1–2 vCPUs) governed by a Horizontal Pod Autoscaler (HPA):     graph TD\n       subgraph Pod[\"1 vCPU Pod: WSGI Threadpool (5 Threads)\"]\n           T1[\"Thread 1: Blocked on Stripe API\"]\n           T2[\"Thread 2: Blocked on Auth Service\"]\n           T3[\"Thread 3: Blocked on Slow DB Lock\"]\n           T4[\"Thread 4: Blocked on Inventory API\"]\n           T5[\"Thread 5: Blocked on S3 Upload\"]\n           Queue[\"Socket Listen Queue: 50+ Inbound Requests Overflowing!\"]\n       end\n  Under WSGI with a 1-vCPU limit:   The formula   min(32, 1 + 4)  allocates   only 5 worker threads .  If just 5 concurrent requests hit a third-party payment gateway, an external auth provider, or an upstream microservice with a 200ms latency spike,   100% of the pod's worker capacity is instantly deadlocked .  Any subsequent incoming requests (including fast health probes) queue in the TCP listen backlog. P95 latency explodes from 200ms to over 3000ms within seconds.   2. The ASGI Socket Multiplexing Advantage in Small Pods  Under ASGI, Hurricane decouples incoming network sockets from OS worker threads through   Granian 's multi-threaded   Tokio Rust event loop :     Pod Resource Quota  WSGI Concurrent In-Flight Sockets  ASGI Concurrent In-Flight Sockets  Architectural Limit     1 vCPU \u002F 1 GiB RAM   5 concurrent requests   Thousands of concurrent sockets  WSGI bounded by threadpool; ASGI bounded by OS file descriptors.    2 vCPUs \u002F 2 GiB RAM   6 concurrent requests   Thousands of concurrent sockets  Tokio event loop multiplexes connections without consuming OS threads.    4 vCPUs \u002F 4 GiB RAM   8 concurrent requests   Thousands of concurrent sockets  Non-blocking coroutines yield during external I\u002FO waits.  Empirical Evidence from the Benchmark Suite  In the benchmark's API Gateway scatter-gather fan-out (  \u002Fapi\u002Fgateway\u002Faggregate ) and external API fetch (  \u002Fexternal\u002Ffetch ) workloads:    WSGI under step load:  When concurrent users exceeded the available thread count, tail latency ($p95$) spiked to   5600 ms  because requests were forced to wait in the OS listen backlog.   ASGI under step load:  Asynchronous coroutines yielded the Tokio event loop during socket waits (  httpx ), keeping tail latencies flat and eliminating the thread-starvation deadlocks that severely degrade WSGI.   3. Preventing Kubernetes Health Probe Flapping Under Load  In high-concurrency Kubernetes clusters, server overload often causes the dreaded   Probe Flapping Death Spiral :     sequenceDiagram\n       autonumber\n       actor Kubelet\n       participant Pod as Overloaded Pod (Port 8000)\n       participant Endpoints as K8s Service Endpoints\n   \n       Note over Pod: Pod receives heavy traffic spike (100% Threads Busy)\n       Kubelet->>Pod: GET \u002Fready (Shared Port 8000)\n       Note over Pod: Probe request queues behind 100 client requests\n       Pod--xKubelet: Connection Timeout (>2s)\n       Kubelet->>Endpoints: Pod marked UNREADY (IP Removed)\n       Note over Endpoints: Remaining Pods absorb shedding traffic and crash too!\n  The Hurricane Solution:    Dedicated Secondary Probe Port (  --probe-port 8001 ) :\nBy binding   \u002Fready ,   \u002Falive , and   \u002Fmetrics  to port   8001 , cluster health probes never queue behind heavy client payloads, large file uploads, or slow view responses on port   8000 .   Shared-Memory Traffic Shedding (  \u002Fready ) :\nHurricane continuously tracks request queue length via lock-free POSIX shared memory (  SharedMetrics ). When the queue depth exceeds   --req-queue-len :\n    \u002Fready  immediately returns   400 Bad Request  in microseconds.  Kubernetes gracefully stops sending new Ingress traffic to the pod.  The container   never restarts , and existing in-flight requests finish cleanly.  Once the queue clears,   \u002Fready  returns   200 OK , and traffic resumes instantly without container restart overhead.   4. Horizontal Pod Autoscaling (HPA) Strategies  The CPU Metric Fallacy in Python Web Services  A common anti-pattern in Kubernetes is relying solely on CPU utilization (  targetCPUUtilizationPercentage: 70 ) for autoscaling:   When worker threads are blocked waiting on network sockets (e.g. database locks, external APIs, S3 uploads),   CPU utilization drops to near zero  because threads are idle in   sleep  or   epoll_wait  state.  Even though the pod is completely deadlocked with an overflowing request queue,   the HPA will not scale up replicas  because CPU utilization appears low!  Recommended Practice: Queue-Based HPA with Prometheus  Use Hurricane's native Prometheus metrics with Prometheus Adapter or KEDA to autoscale based on active queue backlog and probe latency:     apiVersion  :   keda.sh\u002Fv1alpha1\n   kind  :   ScaledObject\n   metadata  :\n     name  :   django-hurricane-autoscaler\n   spec  :\n     scaleTargetRef  :\n       name  :   django-app\n     minReplicaCount  :   3\n     maxReplicaCount  :   20\n     triggers  :\n     -   type  :   prometheus\n       metadata  :\n         serverAddress  :   http:\u002F\u002Fprometheus-k8s.monitoring.svc.cluster.local:9090\n         metricName  :   hurricane_requests_queue_length\n         query  :   sum(hurricane_requests_queue_length{app=\"django-app\"}) \u002F count(hurricane_requests_queue_length{app=\"django-app\"})\n         threshold  :   '10'\n   5. Cost Optimization: Hurricane vs. Gunicorn Memory Tax  In Kubernetes, cloud bills are dictated by   Node RAM and vCPU capacity .  Traditional WSGI servers like Gunicorn fork multiple independent OS processes (  2 * CPUs + 1 ):   Each forked process loads Python runtime, Django models, ORM metadata, caches, and application code into private memory.  In a container with 4 workers, a 200 MB Django app consumes   800 MB to 1 GB of RAM .  Teams are forced to set high memory limits or risk random OOM kills (  SIGKILL  137).  The Hurricane Advantage:   Hurricane executes on a compiled Rust core with multi-threaded workers in a single memory space.  Static and media files are served directly with zero-copy Rust buffers.  Memory consumption per Pod is slashed by   50% to 70% , enabling significantly higher pod density per Kubernetes worker node and cutting cloud infrastructure costs.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":230,"path":231,"dir":206,"title":232,"description":233,"keywords":234,"body":240},"content:4.performance:3.architecture-recommendations.md","\u002Fperformance\u002Farchitecture-recommendations","Conclusions & Architectural Recommendations","Actionable guidelines, architectural decision tree, and production sizing recommendations for deploying Django Hurricane in production.",[235,236,237,238,239],"1. Architectural Decision Tree","2. Workload-Driven Architecture Selection","3. Deep-Dive: Core Architectural Principles","4. Production Deployment Cheat-Sheet","5. Kubernetes Production Flags Checklist","  Conclusions & Architecture Recommendations  The empirical findings from the    Django Hurricane Benchmark Suite  demonstrate that   neither WSGI nor ASGI is universally superior across all Django workloads .  Instead, optimal performance and container resilience depend on whether an application is   relational ORM \u002F CPU bound  or   network I\u002FO \u002F microservice bound , and whether it runs on bare-metal hardware or in constrained Kubernetes Pods.   1. Architectural Decision Tree     graph TD\n       Q{Is your application predominantly:}\n       Q -->|Relational \u002F ORM Heavy\u003Cbr\u002F>CRUD, CMS, Relational DB, Admin| WSGI[WSGI Worker=Auto\u003Cbr\u002F>- Highest DB Speed\u003Cbr\u002F>- Zero Thread Hops\u003Cbr\u002F>- Minimal Median Latency]\n       Q -->|External I\u002FO Heavy\u003Cbr\u002F>Microservices, Upstream APIs, WebSockets| ASGI[ASGI Worker=Auto\u003Cbr\u002F>- Flat Tail Latency\u003Cbr\u002F>- Non-blocking I\u002FO\u003Cbr\u002F>- High Concurrency Resiliency]\n       WSGI --> Sizing[Running in Containers \u002F Kubernetes Pods 1-2 vCPUs\u003Cbr\u002F>ASGI provides decisive socket resiliency\u003Cbr\u002F>preventing threadpool exhaustion under load]\n       ASGI --> Sizing\n   2. Workload-Driven Architecture Selection     Workload Dimension  Dominant Architecture  Behavioral Characteristic  Root Architectural Mechanics     Relational ORM & DB Queries (in Isolation)   WSGI (Worker=Auto)  Substantially higher raw query throughput, minimal median & tail latency.  Multi-threaded WSGI executes synchronous Django ORM queries concurrently across independent database connections without event-loop wrapping overhead.    Server-Side Template Rendering (in Isolation)   WSGI (Worker=Auto)  Consistently faster CPU throughput.  Django Template Language (DTL) is synchronous CPU work. WSGI distributes rendering across OS worker threads without event-loop context-switching overhead.    External APIs & Microservice Fan-Out   ASGI (Clean Async \u002F Forced Sync)  Dramatically lower tail latency ($p95$), zero thread starvation.  Coroutines yield the Tokio event loop during network socket waits (  httpx ); WSGI deadlocks OS worker threads during upstream latency, causing severe queue buildup.    Mixed Real-World Web Traffic   ASGI (Forced Sync Views)  Highest aggregate throughput and lowest median response time.   Granian 's socket multiplexing handles incoming connections non-blockingly, preventing slow network I\u002FO from starving the worker threads needed for database queries.    Cloud-Native Kubernetes Pods (1–2 vCPUs)   ASGI (Forced Sync \u002F Clean Async)  Connection resiliency without threadpool exhaustion.  In constrained pod specs, WSGI's tiny threadpool (5–6 threads) easily chokes on blocking I\u002FO; ASGI handles high connection counts within small CPU\u002Fmemory limits.   3. Deep-Dive: Core Architectural Principles  A. The Relational ORM Concurrency Constraint in ASGI  Django's core ORM is synchronous by design. In standard ASGI, calling asynchronous ORM methods (  acount() ,   aaggregate() ,   acreate() ,   async for ) routes each operation through   asgiref.sync.sync_to_async(thread_sensitive=True) :   Under the hood,   asgiref  processes   thread_sensitive  tasks on a   single shared background thread  (  _max_workers=1 ).  Consequently, on workloads composed primarily of database reads and writes, standard ASGI funnels all concurrent requests through that single thread, creating a bottleneck and adding thread-scheduling and GIL contention overhead.  Under multi-threaded WSGI, each worker thread holds its own synchronous connection via the   psycopg  connection pool, enabling true parallel database queries.   B. The \"Partial Async\" Context-Switching Trap  A consistent empirical finding across the benchmark suite is that    ASGI (Forced Sync Views)  matches or outperforms   ASGI (Clean Async)  on database-intensive endpoints :    Why this occurs : When a view is synchronous (  def view ), Django's ASGI handler dispatches the entire view   once  to a threadpool worker. All database queries, model operations, and response formatting execute within that thread with only a single thread context switch.  In an   async def  view that queries the standard ORM, each query call repeatedly yields to the event loop and hops across the threadpool boundary. A single request incurs multiple context switches and GIL re-acquisitions.   Actionable Rule : Do not convert Django views to   async def  simply because ASGI is enabled. Only declare a view   async def  if it genuinely awaits non-blocking asynchronous operations (such as   httpx ,   aiofiles , or Redis).   C. The Single-Threaded Deployment Hazard (  Worker=1 )  Single-threaded deployments for either WSGI or ASGI (  Worker=1 ) should   never be used in production :   A single-threaded WSGI server completely freezes during any blocking upstream network call or slow database lock.  A single-threaded ASGI server starves background tasks (such as template rendering and non-sensitive async offloading) of threadpool capacity.   Actionable Rule : Always deploy servers with auto-threading enabled (  Worker=Auto ), allowing Hurricane to scale blocking threads dynamically:   min(32, CPU + 4) .   D. The Role of Specialized Async ORM Backends (  django-async-backend )  Bypassing   asgiref  by routing queries through   Product.async_objects  directly over non-blocking   psycopg 3  connection pools eliminates threadpool hops. However, asynchronous database pools require strict event-loop lifecycle discipline and are sensitive to pool exhaustion under heavy step load.  It remains a specialized optimization for isolated microservices rather than a drop-in replacement for general-purpose monolithic Django applications.   4. Production Deployment Cheat-Sheet     Deployment Scenario  Recommended Architecture  Primary Advantages  When to Choose     Kubernetes Microservice \u002F API Gateway   ASGI (Worker=Auto \u002F Clean Async)  Flat tail latency on network I\u002FO, non-blocking scatter-gather fan-out (  asyncio.gather ), high connection capacity in small pod specs (1–2 vCPUs).  Containerized Kubernetes services calling upstream APIs, payment providers, third-party webhooks, or streaming responses.    Monolithic \u002F Relational Web App (Dedicated Nodes)   WSGI (Worker=Auto \u002F Multi-Thread)  Maximum raw database query throughput, lowest median latency for ORM endpoints, parallel database execution with zero event-loop hopping.  Classic monolithic Django applications on dedicated multi-core instances dominated by ORM queries, Django admin, forms, and DTL templates.    Existing WSGI App Modernizing on Kubernetes   ASGI (Forced Sync Views)  Immediate socket multiplexing gains in small pods, zero view code refactoring, avoids multi-hop async ORM context switches.  Transitional migration phase from legacy WSGI servers to Hurricane in Kubernetes before refactoring views to native async.    Isolated Greenfield Microservice   ASGI +   django-async-backend  Direct non-blocking database queries via   Product.async_objects  over   psycopg 3  connection pools.  Greenfield microservices with full control over query design and zero dependency on third-party synchronous Django apps.    Single-Threaded Baseline   WSGI (  Worker=1 ) \u002F ASGI (  Worker=1 )  Diagnostic baseline only.   Never in production.  Highly vulnerable to thread starvation and head-of-line blocking under real traffic.   5. Kubernetes Production Flags Checklist  When deploying Hurricane in production Kubernetes clusters, verify these CLI flags:     python   manage.py   serve   \\\n     --port=8000   \\\n     --probe-port=8001   \\\n     --workers=auto   \\\n     --req-queue-len=50   \\\n     --check-migrations-apply   \\\n     --fast-404   \\\n     --rate-limit\n     --probe-port 8001 : Isolates health probes and Prometheus scrapes from client traffic on port   8000 .    --workers auto : Automatically calculates optimal worker thread pool depth (  min(32, CPU + 4) ).    --req-queue-len 50 : Tells   \u002Fready  to return HTTP 400 when worker queue exceeds 50 requests, preventing ingress overload.    --check-migrations-apply : Prevents   \u002Fstartup  from reporting 200 OK until database schema is verified and applied.    --fast-404 : Drops bot\u002Fscanner requests in microseconds before hitting Django middleware or the database.    --rate-limit : Token-bucket volumetric defense against traffic spikes and denial-of-service attempts.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":242,"path":243,"dir":244,"title":245,"description":246,"keywords":247,"body":254},"content:5.roadmap:1.feature-roadmap.md","\u002Froadmap\u002Ffeature-roadmap","roadmap","Product Roadmap","The technical vision and upcoming features for Hurricane: HTTP Accelerator, Background Tasks & Cron, Early Hints, and Circuit Breakers.",[248,249,250,251,252,253],"Roadmap Overview","1. Django-Native HTTP Accelerator (Varnish Replacement)","2. Built-in Background Tasks & Cron (\"Celery-Lite\")","3. HTTP 103 Early Hints","4. Circuit Breakers & Graceful Degradation","Get Involved & Shape the Roadmap","  Product Roadmap  Hurricane 2.0 reimagined what a modern Django application server can be by combining Granian's high-performance Rust networking with Django-native intelligence, edge security shields, and native asset streaming.  Our roadmap focuses on expanding Hurricane into a   complete, all-in-one production runtime  for Django—replacing bloated multi-container stacks (Gunicorn + Nginx + Varnish + Celery) with a single, resilient application server.   Roadmap Overview     Pillar  Feature  Target Scope  Impact     Performance    1. Django-Native HTTP Accelerator  Varnish Replacement  Full-page caching, SWR, tag invalidation via Django signals.    Simplicity    2. Background Tasks & Cron  Celery-Lite  Native Django Tasks backend, cron scheduler, multi-pod locking.    Browser Speed    3. HTTP 103 Early Hints  Asset Preloading  Stream preloads while Django renders; pending Granian upstream.    Resilience    4. Circuit Breakers & Degradation  Outage Protection  Edge traffic shedding and fallback on database outages.   1. Django-Native HTTP Accelerator (Varnish Replacement)  The Challenge  High-traffic content portals, e-commerce stores, and media applications often place   Varnish Cache  in front of Django to survive traffic surges. While Varnish is fast, it introduces massive operational complexity:   Writing and debugging esoteric   VCL (Varnish Configuration Language) .  Difficult SSL\u002FTLS termination and multi-container routing.   Brittle Cache Invalidation : Invalidating cache entries via custom HTTP   PURGE  or   BAN  headers often gets out of sync with Django model mutations, leading to stale content or cache stampedes.  The Hurricane Solution  Hurricane will introduce an embedded   Tier 2 HTTP Accelerator  running directly in the gateway layer before requests enter the Python worker pool.     graph TD\n       Req[\"Incoming HTTP Request\"] --> AccelCheck{\"Cached in Hurricane?\u003Cbr\u002F>Shared Memory \u002F Redis\"}\n       AccelCheck -- Cache Hit (&lt; 0.05ms) --> ServeCached[\"Serve Accelerated Response\u003Cbr\u002F>Directly from Edge\"]\n       AccelCheck -- Expired (SWR) --> ServeStale[\"Serve Stale Content Instantly\"]\n       ServeStale --> AsyncRefresh[\"Background Thread:\u003Cbr\u002F>Revalidate with Django\"]\n       AccelCheck -- Cache Miss --> ForwardDjango[\"Process in Django\"]\n       ForwardDjango --> StoreCache[\"Store in Cache Backend\u003Cbr\u002F>Apply Surrogate-Key Tags\"]\n       StoreCache --> ReturnClient[\"Return Response to Client\"]\n  Key Capabilities    Surrogate-Keys & Tag-Based Invalidation :\nInstead of brittle URL-based purging, views assign semantic tags:     from   hurricane.accelerator   import   accelerate\n   \n   \n   @accelerate  (  ttl  =  3600  ,   tags  =  [  \"article:102\"  ,   \"author:jane\"  ,   \"category:news\"  ])\n   def   article_detail  (request, slug):   ...\n  When an article or author is updated in the Django admin or via ORM, a standard   post_save  signal triggers:     from   hurricane.accelerator   import   purge_tags\n   \n   \n   def   on_article_saved  (sender, instance,   **  kwargs):\n       purge_tags(  f  \"article:  {  instance.pk  }  \"  ,   \"category:news\"  )\n  Hurricane instantly purges or marks all matching pages stale across the cluster with zero network roundtrips.   Stale-While-Revalidate (SWR) & Stale-If-Error :\nWhen a cached page reaches its expiration time, Hurricane serves the stale response in   \u003C 0.05 ms  while asynchronously triggering a background task to refresh the page with Django. If the database is undergoing a brief migration or outage,   stale-if-error  continues serving visitors without throwing 500 errors.   Built-in Django Cache Framework Integration :\nThe accelerator stores cached responses directly in Django's configured cache framework (  django.core.cache.caches[\"accelerator\"] ):    Single Pod \u002F Dev : Local-memory or POSIX shared memory.   Multi-Pod Kubernetes : Shared Redis, Valkey, or Memcached clusters for instant cross-replica synchronization.   Declarative Global Route Rules :\nConfigure caching policies across entire URL patterns in   settings.py  without touching view code:     HURRICANE_ACCELERATOR   =   {\n       \"ENABLED\"  :   True  ,\n       \"CACHE_BACKEND\"  :   \"default\"  ,\n       \"ROUTES\"  : [\n           {  \"pattern\"  :   r  \"  ^  \u002Fapi\u002Fv1\u002Fcatalog\u002F  \"  ,   \"ttl\"  :   300  ,   \"swr\"  :   60  },\n           {  \"pattern\"  :   r  \"  ^  \u002Fblog\u002F  \"  ,   \"ttl\"  :   3600  ,   \"swr\"  :   300  },\n       ],\n   }\n   2. Built-in Background Tasks & Cron (\"Celery-Lite\")  The Challenge  Most Django applications only need to run periodic cleanup tasks (  clearsessions , inventory imports) or defer lightweight background jobs (sending transactional emails, processing webhooks, resizing an avatar).  Today, this requires deploying   Redis, a Celery worker container, and a Celery Beat scheduler —adding 3+ containers, hundreds of megabytes of RAM overhead, and complex worker monitoring.  The Hurricane Solution  Hurricane will provide a   zero-infrastructure background task and cron engine  embedded directly into the application server process, fully aligned with the upcoming   Django Background Tasks interface (DEP 0014) .     graph TD\n       subgraph ServerProcess[\"Hurricane Server Process\"]\n           HTTP[\"Granian HTTP Workers\"] -->|tasks.enqueue| Queue[\"Internal Job Queue\"]\n           Cron[\"Embedded Cron Scheduler\"] -->|Evaluates Schedules| Queue\n           Queue --> LockCheck{\"Acquire Distributed Lock?\u003Cbr\u002F>PostgreSQL Advisory \u002F Redis\"}\n           LockCheck -- Acquired --> WorkerPool[\"Isolated Task ThreadPool\"]\n           LockCheck -- Not Acquired --> Skip[\"Skip: Already Running on Sibling Pod\"]\n           WorkerPool --> Prometheus[\"Emit Task Metrics to \u002Fmetrics\"]\n       end\n  Key Capabilities    DEP 0014 Native Task Backend :\nImplement the official Django background tasks backend specification:     from   django.tasks   import   task\n   \n   \n   @task  ()\n   def   send_welcome_email  (user_id:   int  ):\n       user   =   User.objects.get(  pk  =  user_id)\n       user.email_user(  \"Welcome!\"  ,   \"Thank you for joining...\"  )\n   \n   \n   # In a view:\n   send_welcome_email.enqueue(new_user.id)\n   Embedded Cron Scheduler :\nDeclare periodic tasks directly in   settings.py  supporting standard cron syntax, human shortcuts, and management command execution:     HURRICANE_CRON   =   [\n       # Built-in Django command\n       {\n           \"name\"  :   \"clearsessions\"  ,\n           \"schedule\"  :   \"0 3 * * *\"  ,    # Every night at 3:00 AM\n           \"command\"  :   \"clearsessions\"  ,\n       },\n       # Custom command with arguments\n       {\n           \"name\"  :   \"sync-catalog\"  ,\n           \"schedule\"  :   \"*\u002F15 * * * *\"  ,    # Every 15 minutes\n           \"command\"  :   \"sync_inventory\"  ,\n           \"args\"  : [  \"--source=erp\"  ,   \"--verbose\"  ],\n       },\n       # Direct Python callable\n       {\n           \"name\"  :   \"heartbeat\"  ,\n           \"schedule\"  :   \"@hourly\"  ,\n           \"task\"  :   \"myapp.tasks.ping_uptime_monitor\"  ,\n       },\n   ]\n   Multi-Pod Duplicate Prevention (Distributed Advisory Locks) :\nWhen 10 Kubernetes pods run Hurricane simultaneously, only   one  pod executes the scheduled job. Hurricane acquires lightweight database advisory locks (  SELECT pg_try_advisory_lock(...)  on PostgreSQL,   GET_LOCK()  on MySQL) or atomic Redis cache locks (  SET NX ). Zero duplicate runs.   Efficient Long-Running Task Delays (Spanning Multiple Days) :\nSchedule tasks days or weeks into the future (e.g.   send_followup.enqueue(user_id, delay=timedelta(days=7)) ). Tasks are stored with scheduled timestamps in the database or Redis index, sleeping efficiently without holding idle worker threads open.   Deep Prometheus Observability :\nEvery task and cron job emits metrics to   \u002Fmetrics  for real-time Grafana monitoring:    hurricane_task_execution_seconds{task=\"send_welcome_email\"}  (Histograms)   hurricane_task_failures_total{task=\"sync-catalog\"}  (Failure counters)   hurricane_cron_last_run_timestamp{job=\"clearsessions\"}   3. HTTP 103 Early Hints  The Challenge  When a browser requests an HTML page, it must wait for Django to connect to the database, render the template, and stream the HTML back before discovering what CSS stylesheets, JavaScript bundles, and web fonts it needs to download. This creates an avoidable 50–200 ms rendering bottleneck where the browser's network pipe sits idle.  The Hurricane Solution   HTTP 103 Early Hints  allows the server to send an informational response with   \u003Clink rel=\"preload\">  headers   immediately upon receiving the request , while Django is still processing the view.     sequenceDiagram\n       autonumber\n       actor Browser as Client Browser\n       participant Gateway as Hurricane Gateway\n       participant Django as Django Backend\n   \n       Browser->>Gateway: GET \u002Fproducts\u002F\n       Gateway->>Django: Forward Request\n       Note over Django: Django queries DB & renders template...\n       Gateway-->>Browser: HTTP 103 Early Hints\u003Cbr\u002F>Link: \u002Fstatic\u002Fapp.css (preload)\u003Cbr\u002F>Link: \u002Fstatic\u002Ffont.woff2 (preload)\n       Note over Browser: Browser fetches CSS & fonts in background\n       Django->>Gateway: HTTP 200 OK + HTML Body\n       Gateway->>Browser: HTTP 200 OK + HTML Body\n  Current Technical Status & Roadmap Plan    Current Limitation : Granian proxies HTTP traffic using the Python ASGI\u002FWSGI specifications, which do not currently expose an informational 1xx streaming response API to Python applications.   Roadmap Path : We are collaborating with the Granian and Hyper ecosystem to introduce informational response support. Hurricane's configuration interface and   @early_hints  decorators are designed and ready to be connected once Granian exposes 103 streaming hooks over HTTP\u002F2 and HTTP\u002F3.   4. Circuit Breakers & Graceful Degradation  The Challenge  When a PostgreSQL database reaches its connection pool limit or a third-party microservice experiences an outage, incoming traffic continues piling into Django worker threads. Requests hang until they hit reverse proxy timeouts, creating a cascading failure that prevents the database from recovering.  The Hurricane Solution  An integrated   Edge Circuit Breaker  that monitors error rates and connection failures at the gateway layer, protecting backend resources from collapse.     graph LR\n       Closed[\"Circuit Closed\u003Cbr\u002F>Normal Operation\"] -->|Error rate &gt; 25%\u003Cbr\u002F>or 5 consecutive DB errors| Open[\"Circuit Open\u003Cbr\u002F>Edge Traffic Shedding\"]\n       Open -->|Cool-off timer expires| HalfOpen[\"Half-Open\u003Cbr\u002F>Canary Probe Traffic\"]\n       HalfOpen -->|Canary requests succeed| Closed\n       HalfOpen -->|Canary fails| Open\n  Key Capabilities    Automated Circuit Tripping :\nIf database connection failures (  OperationalError ) or 5xx error rates exceed a configurable threshold within a sliding time window (e.g. 5 consecutive database drops in 3 seconds), the circuit opens immediately.   Instant Edge Traffic Shedding :\nWhen the circuit is open, incoming requests are shed at Tier 2 in   \u003C 0.35 microseconds  without touching Django worker threads or opening database connections.   Graceful Degradation :\n   Serves cached responses from the   HTTP Accelerator  (stale-if-error).  Returns clean, styled maintenance pages with   Retry-After  headers.   Self-Healing Canary Probes :\nAfter a cool-off interval (e.g. 10 seconds), the circuit transitions to   Half-Open , permitting a small percentage of canary requests through to test database health. Once the database recovers, normal traffic resumes automatically.   Kubernetes Probe Coordination :\nWhen the circuit trips, Hurricane temporarily sets the   \u002Fready  probe to   HTTP 400 , instructing Kubernetes Ingress and AWS ALBs to divert traffic to healthy sibling pods until recovery completes.   Get Involved & Shape the Roadmap  Hurricane is an open-source, community-driven project. We welcome your feedback, use cases, and code contributions:   💬   Join the Discussion:  Chat with us on the   Blueshoe Discord Server .  💡   Feature Requests:  Open an issue or discussion on   GitHub .  🏢   Commercial Collaboration:  Partner with the core team at   Blueshoe  to sponsor or co-develop roadmap initiatives.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":256,"path":257,"dir":7,"title":258,"description":259,"keywords":260,"body":267},"content:data-privacy.md","\u002Fdata-privacy","Privacy Policy","Information on how personal data is handled on django-hurricane.io and related documentation.",[261,262,263,264,265,266],"Introduction","Controller within the meaning of the GDPR","Web Hosting & Server Log Files","No Marketing Tracking, No Cookies","Contact by Email","Your Rights under the GDPR","  Privacy Policy  Information on how we handle personal data on this website and documentation.  Introduction  Thank you for your interest in Django Hurricane. Protecting your personal data is important to us. Below you will find information about how we handle data collected through your use of this documentation website. Your data is processed in accordance with applicable data protection law, in particular the General Data Protection Regulation (GDPR) and the German Federal Data Protection Act (BDSG).   Controller within the meaning of the GDPR   Blueshoe GmbH  \nBahnhofstraße 3a  \n82166 Gräfelfing  \nGermany    Phone:  +49 (0)89 54197872   Email:    hurricane@blueshoe.io  \u002F   hello@blueshoe.io  Data Protection Officer  Proliance GmbH \u002F   www.datenschutzexperte.de  \nData Protection Officer  \nLeopoldstr. 21  \n80802 Munich  \nGermany  \nEmail:   datenschutzbeauftragter@datenschutzexperte.de   Web Hosting & Server Log Files  This documentation website is hosted as static content. When you visit our website, technical data is automatically transmitted from your browser to the web server:   Date and time of the request  Name of the requested file or resource  Page from which the file was requested (referrer URL)  Access status \u002F HTTP status code  Browser type and operating system used  IP address of the requesting device  Amount of data transferred  We collect this data to ensure a stable connection, secure operation, and administrative purposes. The legal basis is   Art. 6(1)(f) GDPR  (legitimate interest in providing a reliable, secure service). For technical security reasons, in particular to defend against attacks, this data may be stored temporarily in server logs and is subsequently deleted or anonymized.   No Marketing Tracking, No Cookies    No Cookies:  We do not use advertising, marketing, or profiling cookies.   Local Storage:  The documentation site uses browser   localStorage  solely to store user interface preferences (such as light\u002Fdark color mode preference). The legal basis is   Art. 6(1)(f) GDPR  and Section 25(2) TDDDG.   Local Fonts:  All typography and font assets are served locally from our static deployment. No connections to external Google Font servers are established.   Contact by Email  If you contact us by email (e.g., at   hurricane@blueshoe.io ), we process your contact details and message to handle your inquiry and any follow-up questions. The legal basis is   Art. 6(1)(f) GDPR  (legitimate interest in responding to user inquiries). Your data will be deleted once your inquiry has been fully resolved, unless statutory retention obligations apply.   Your Rights under the GDPR  Under the General Data Protection Regulation, you have the following rights vis-à-vis the controller:    Right of Access  pursuant to Art. 15 GDPR   Right to Rectification  pursuant to Art. 16 GDPR   Right to Erasure  pursuant to Art. 17 GDPR   Right to Restriction of Processing  pursuant to Art. 18 GDPR   Right to Data Portability  pursuant to Art. 20 GDPR   Right to Object  pursuant to Art. 21 GDPR   Right to Lodge a Complaint  with a supervisory authority pursuant to Art. 77 GDPR  To exercise any of your rights or request information, please contact us at   hurricane@blueshoe.io .",{"id":269,"path":270,"dir":7,"title":271,"description":272,"keywords":273,"body":276},"content:legal-notice.md","\u002Flegal-notice","Legal Notice","Provider identification and legal notices for Django Hurricane.",[274,275],"Provider Identification according to § 5 TMG","Disclaimer of Liability","  Legal Notice  Provider Identification according to § 5 TMG   Blueshoe GmbH  \nBahnhofstraße 3a  \n82166 Gräfelfing  \nGermany  Represented by   Michael Schilonka  Robert Stein  Contact    Phone:  +49 (0)89 54197872   Email:    hello@blueshoe.io   Website:    www.blueshoe.io  Commercial Register    Register Court:  Munich District Court (Amtsgericht München)   Register Number:  HRB 215552   VAT Identification Number:  DE297801323   Disclaimer of Liability  Liability for Content  The contents of our pages and documentation were created with great care. However, we cannot assume any liability for the correctness, completeness, and topicality of the content. As a service provider, we are responsible for our own content on these pages in accordance with general statutory laws pursuant to Section 7 (1) of the German Telemedia Act (TMG).  According to §§ 8 to 10 TMG, as a service provider, we are not obliged to monitor transmitted or stored third-party information or to investigate circumstances that indicate illegal activity. Obligations to remove or block the use of information according to general laws remain unaffected. However, liability in this regard is only possible from the time of knowledge of a concrete infringement. Upon becoming aware of such legal violations, we will remove this content immediately.  Liability for Links  Our documentation and website contain links to external third-party websites over whose content we have no influence. Therefore, we cannot accept any liability for this third-party content. The respective provider or operator of the linked pages is always responsible for their content. The linked pages were checked for possible legal violations at the time of linking. No illegal content was recognizable at that time. A permanent control of the content of the linked pages is not reasonable without concrete indications of an infringement. Upon notification of violations, we will remove such links immediately.  Copyright  The content and works published on this website and in the documentation are subject to copyright law. Duplication, processing, distribution, or any form of commercialization beyond the scope of the copyright law requires the prior written consent of its respective author or creator.  Django Hurricane is licensed under the terms of the open-source   MIT License .",1793640720377]