[{"data":1,"prerenderedAt":236},["ShallowReactive",2],{"search-api":3},[4,17,29,39,51,64,75,93,106,117,126,136,145,154,166,176,190,202,214,227],{"id":5,"path":6,"dir":7,"title":8,"description":7,"keywords":9,"body":16},"content:0.index.md","\u002F","","Django Hurricane - Kubernetes-Native Application Server for Django",[10,11,12,13,14,15],"Latest Release","Built for Production Excellence","The Django + Kubernetes Advantage","Proven Track Record","Quickstart","Community & Support","    🚀   Version 2.0.0rc2 is live!    Explore the release & PyPI package ↓   Kubernetes-Supercharged Django Applications   The battle-tested, cloud-native application server built specifically to integrate Django seamlessly with Kubernetes. Zero-configuration deployment, deep health probe lifecycles, edge security shields, and real-time Prometheus observability.  Latest Release    Built for Production Excellence    Dedicated probe server running on port 8001 with   \u002Fstartup ,   \u002Falive , and   \u002Fready  endpoints. Prevents pod restarts during long database migrations and automatically sheds Ingress traffic under queue congestion.   Instantly drops automated scanners (probing for   .php ,   \u002F.env ,   \u002Fwp-admin\u002F ) at the gateway in microseconds. Protects Django middleware, session caches, and database connection pools from bot scans.   Gateway rate limiting with client IP extraction via   X-Forwarded-For  for Kubernetes Ingress and load balancers. Silently drops volumetric floods with zero log spam to prevent log-based Denial of Service.   Built-in   \u002Fmetrics  exposition scraping request counts, latency averages, and queue depth. POSIX shared memory buffers aggregate cross-worker state atomically with sub-microsecond overhead.   Drop into your existing project with   python manage.py serve . Hurricane auto-detects   WSGI_APPLICATION  or   ASGI_APPLICATION  from your Django settings without complex config files.   Asynchronous webhook dispatches notifying monitoring services, Slack, or orchestrators when pods complete startup, experience deadlock health failures, or initiate graceful termination.   The Django + Kubernetes Advantage  Django was developed with a batteries-included philosophy and gracefully handles complex web application challenges. However, modern infrastructure requires cloud-native patterns: ephemeral containers, dynamic autoscaling, and real-time health feedback.  It's Not Just About Running in a Cluster  Anyone can run Django in a container behind Gunicorn. But Kubernetes requires more:    Migration Synchronization:  Database migrations run during pod startup must not be slain by aggressive readiness timers.   Traffic Shedding:  When a pod's worker queue is temporarily saturated, Kubernetes should divert traffic to siblings rather than terminating the container.   Deadlock Detection:  When worker threads hang on an unresponsive database socket, the server should signal the kubelet to restart the container automatically.   Edge Attack Immunity:  Automated bot vulnerability scans (  wp-login.php ,   .env ) should never consume Django database connections or worker threads.  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   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.0rc2\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":78,"title":79,"description":80,"keywords":81,"body":92},"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.",[82,83,84,85,86,87,88,89,90,91],"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 .  MODE   Application execution mode. Supported values:   auto ,   wsgi ,   asgi . In   auto  mode, Hurricane automatically detects whether   ASGI_APPLICATION  is set in your Django settings and runs ASGI; otherwise, it runs standard WSGI.  WORKERS   Number of native OS worker threads used to handle request concurrency. 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. In ASGI mode, defaults to detected container CPUs (capped at 4) to prevent CFS quota throttling in small pods. In WSGI mode, defaults to 1.  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 serving collected static files directly through the gateway using   STATIC_URL  and   STATIC_ROOT  from Django settings.  MEDIA   Enables serving media files directly through the gateway using   MEDIA_URL  and   MEDIA_ROOT  from Django settings.  STATIC_WATCH   List of directories to watch for changes during development; automatically triggers   collectstatic  when changes occur.   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, otherwise signature matching. 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.  FAST_404_EXTRA_PREFIXES   List of additional URL path prefixes to drop immediately at the gateway.   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":94,"path":95,"dir":96,"title":97,"description":98,"keywords":99,"body":105},"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.",[100,101,102,103,104],"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 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 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":107,"path":108,"dir":96,"title":109,"description":110,"keywords":111,"body":116},"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.",[112,113,114,115],"Architecture Overview","Why Rust Over Python Event Loops?","Zero-Config WSGI & ASGI Auto-Detection","⚡ 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 Rust Core (Granian)\n           Hyper\n           Tokio\n       end\n   \n       Tokio -->|Zero-Copy Dispatch| Gateway[Hurricane Base Gateway]\n   \n       subgraph 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 WSGI & ASGI Auto-Detection  Hurricane automatically inspects your Django configuration on boot and switches to the optimal engine without requiring manual flags:     graph TD\n       Start[Server Bootstrap] --> Check{Is ASGI_APPLICATION defined in settings?}\n       Check -- Yes --> InitASGI[Initialize HurricaneASGIGateway with ASGIWorker]\n       Check -- No --> InitWSGI[Initialize HurricaneWSGIGateway with WSGIWorker]\n       InitASGI --> Serve[Serve Traffic with Hurricane]\n       InitWSGI --> Serve\n    Classic Django Projects:  If   WSGI_APPLICATION = \"myproject.wsgi.application\"  is present, Hurricane boots with its multithreaded Rust WSGI engine (using Granian's   WSGIWorker ).   Async & Channels Projects:  If   ASGI_APPLICATION = \"myproject.asgi.application\"  is configured, Hurricane automatically runs with its asynchronous Rust ASGI engine (using Granian's   ASGIWorker ).   Manual Override:  You can force a specific execution mode via the   --mode  flag (or   MODE  in   settings.py ):\n     python   manage.py   serve   --mode=asgi\n  (The legacy   --interface  flag remains supported as an alias).   ⚡ 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.   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":118,"path":119,"dir":96,"title":120,"description":121,"keywords":122,"body":125},"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.",[123,124],"Decision Flowchart","How It Works Internally","  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   \u003C 50 microseconds , completely bypassing Django's middleware pipeline, database pool, and template rendering engine.   Decision Flowchart     graph TD\n       Req[Incoming HTTP Request] --> ProbeCheck{Is Cluster Probe?}\n       ProbeCheck -- Yes --> ServeProbe[Serve Probe Directly]\n       ProbeCheck -- No --> SigCheck{Matches Anti-Django Signature?\u003Cbr\u002F>.php, .env, .git, wp-*, cgi-bin}\n       SigCheck -- Yes --> DropFast404[SILENT DROP: Return Cached 404\u003Cbr\u002F>Latency: &lt; 50µ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 --> DropFast404\n       PrefixCheck -- Yes --> ForwardDjango\n   How It Works Internally  1. Predefined Anti-Django Signature Matching  Hurricane ships with an optimized regular expression containing 31+ attack patterns that Django would never legitimately serve:    Non-Python Script Extensions:    .php[0-9]? ,   .asp[x]? ,   .jsp[x]? ,   .cgi ,   .pl ,   .action ,   .do .   Sensitive Config & Secrets:    \u002F.env* ,   \u002F.git\u002F* ,   \u002F.svn\u002F* ,   \u002F.aws\u002F* ,   \u002F.docker\u002F* ,   \u002Fweb.config .   Common Scanner Targets:    \u002Fwp-* ,   \u002Fwordpress ,   \u002Fxmlrpc.php ,   \u002Fphpmyadmin ,   \u002Fpma ,   \u002Fadmin.php ,   \u002Feval-stdin.php .   Remote Code Execution Probes:    \u002Fcgi-bin\u002F* ,   \u002Factuator\u002F* ,   \u002Fsolr\u002F* ,   \u002Fvendor\u002Fphpunit\u002F* .  2. Prefix Whitelisting  For standard Django applications, Hurricane walks   urlpatterns  recursively at startup to extract all valid top-level path segments (e.g.   {\"\", \"admin\", \"api\", \"accounts\", \"media\", \"static\"} ). Any request with an unknown top-level segment (e.g.,   \u002Funknown-exploit\u002Fpath ) is dropped immediately.  3. CMS & Dynamic Route Auto-Detection  If your Django application uses dynamic database-driven routing with a root catch-all (like   Wagtail ,   django-cms , or   path(\"\u003Cpath:slug>\", ...) ):   Hurricane detects the root wildcard on boot.  Hurricane automatically switches to   Signature-Only Mode .  Legitimate CMS page slugs (e.g.   \u002Fcompany\u002Fabout-us\u002F ) are forwarded to Django normally, while attack probes (  \u002F.env ,   \u002Fwp-login.php ) remain blocked.  4. Bootstrap 404 Pre-Rendering  To ensure total visual fidelity with zero runtime cost, Hurricane renders your site's configured   handler404  (custom or default) once during server bootstrap using a synthetic request. The rendered HTML   bytes  and headers are cached in memory for zero-allocation serving.  5. Silent Operation (Zero Log Spam)  During an attack of 50,000 requests\u002Fsecond, writing log lines can crash log forwarders and exhaust node disk space. Hurricane drops Fast-404 requests   silently  without writing access logs, while updating Prometheus metrics (  RequestCounterMetric ) for Grafana observability.  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":127,"path":128,"dir":96,"title":129,"description":130,"keywords":131,"body":135},"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.",[132,133,134],"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 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":137,"path":138,"dir":96,"title":139,"description":140,"keywords":141,"body":144},"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.",[142,143],"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":146,"path":147,"dir":96,"title":148,"description":149,"keywords":150,"body":153},"content:3.concepts:6.webhooks.md","\u002Fconcepts\u002Fwebhooks","Lifecycle Webhooks","Asynchronous HTTP notifications for pod lifecycle state changes and health transitions.",[151,152],"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":155,"path":156,"dir":96,"title":157,"description":158,"keywords":159,"body":165},"content:3.concepts:7.asgi-vs-wsgi.md","\u002Fconcepts\u002Fasgi-vs-wsgi","ASGI vs. WSGI Architecture","Understand the concurrency models, Hurricane execution layers, and readiness probe differences between ASGI and WSGI deployments.",[160,161,162,163,164],"Architecture Comparison","Hurricane Concurrency Models","Readiness Probing: Queue Backlog vs. Loop Lag","When to Choose WSGI vs. ASGI","Common ASGI Pitfalls in Django","  ASGI vs. WSGI Architecture  Django Hurricane supports both   WSGI  (Web Server Gateway Interface) and   ASGI  (Asynchronous Server Gateway Interface) runtimes through its high-performance Rust engine, powered by    Granian .  Understanding the fundamental differences between these two execution models ensures optimal concurrency, resource utilization, and health monitoring in production.   Architecture Comparison     Feature  WSGI (  --mode wsgi )  ASGI (  --mode asgi )     Paradigm  Synchronous, blocking request-per-thread  Asynchronous, non-blocking coroutines    Concurrency Engine  Python worker threadpool (  blocking_threads )  Rust Tokio event loop (  runtime_threads ) + threadpool    I\u002FO Handling  Synchronous socket polling under GIL  Multi-core work-stealing async scheduler in Rust    WebSockets & SSE  ❌ Not supported  ✅ Native support    Async Views (  async def )  ❌ Executed synchronously via adapter  ✅ Executed natively on event loop    Readiness Probing  Request queue depth (  --req-queue-len )  Event Loop Lag Tracking (  HURRICANE_LOOP_LAG_THRESHOLD )   Hurricane Concurrency Models  Hurricane manages concurrency through three distinct layers (powered by Granian's Rust runtime):     graph TD\n       Client[Incoming Client Requests] --> RustCore[Hurricane Rust Core: Hyper\u002FTokio via Granian]\n   \n       subgraph WSGI Mode\n           RustCore -->|HTTP Dispatch| PyThreadPool[Python Blocking Threadpool]\n           PyThreadPool --> DjangoWSGI[Django WSGI App]\n       end\n   \n       subgraph ASGI Mode\n           RustCore -->|Async Coroutines| TokioLoop[Tokio Event Loop]\n           TokioLoop --> DjangoASGI[Django ASGI App]\n           DjangoASGI -.->|sync_to_async| PyThreadPool\n       end\n  1. The WSGI Concurrency Model  In WSGI mode, Django code is strictly synchronous:   Each incoming HTTP connection is dispatched to an available worker thread in Hurricane's worker thread pool (  blocking_threads ).  While a request waits on a database query, file I\u002FO, or an external API response, that worker thread is completely blocked.   Concurrency Capacity:  Strictly bounded by the thread pool:   Max In-Flight Requests =   blocking_threads . Any additional requests exceeding this pool queue in the socket backlog.  2. The ASGI Concurrency Model  In ASGI mode, requests are received and driven by the multi-threaded   Tokio async runtime :   Asynchronous views (  async def ) and non-blocking I\u002FO operations yield control to the event loop, multiplexing thousands of concurrent connections on a few OS threads.  In ASGI mode,   --runtime-threads  automatically defaults to the number of available CPU cores (up to 16), allowing Hurricane's Rust runtime to schedule async tasks across all physical cores.  When an ASGI view invokes synchronous Django models or legacy sync functions, Django offloads the work to   blocking_threads  via   sync_to_async .   Readiness Probing: Queue Backlog vs. Loop Lag  Because the execution models differ fundamentally, Hurricane monitors health and enforces Kubernetes readiness shedding differently depending on the active mode:  WSGI: Threadpool Backlog (  --req-queue-len )  In WSGI, each concurrent request consumes a thread. If all worker threads are busy, incoming requests queue in the socket backlog.  Hurricane tracks this backlog atomically in POSIX shared memory (  \u002Fdev\u002Fshm ). When backlog exceeds   --req-queue-len  (default: 10),   \u002Fready  returns   HTTP 400 Bad Request , signaling Kubernetes to temporarily withdraw the pod from load-balanced endpoints until worker threads free up.  ASGI: Event Loop Lag Tracking  In ASGI, active coroutines are non-blocking; thousands of concurrent WebSocket connections or async HTTP requests can sit idle on a single thread with zero queue backlog. Subtracting thread counts from coroutines would create false-positive probe failures.  Instead, Hurricane ASGI uses an   Event Loop Lag Tracker :   An internal monitor evaluates event loop scheduling responsiveness every 50ms (  asyncio.sleep(0.05) ).  When the event loop is responsive, scheduling latency (lag) remains near 0ms.  If synchronous CPU-bound operations or saturated async tasks starve the event loop, lag rises.  If event loop lag exceeds   HURRICANE_LOOP_LAG_THRESHOLD  (default: 200ms),   \u002Fready  returns   HTTP 400 , shedding traffic until the loop recovers.   The   --req-queue-len  option is strictly a WSGI parameter. If explicitly passed when running in ASGI mode, Hurricane logs a startup warning indicating that   --req-queue-len  is ignored in favor of Event Loop Lag Tracking.   When to Choose WSGI vs. ASGI     Your application consists of standard, synchronous Django views and Django REST Framework endpoints.  You rely entirely on traditional relational database queries without async ORM drivers.  Maximum single-request CPU performance for synchronous code execution is required.  You have no WebSockets, SSE, or streaming response requirements.    Your application uses   WebSockets  (e.g. Django Channels, chat, real-time dashboards).  You utilize   Server-Sent Events (SSE)  or long-lived streaming responses.  Your views make concurrent non-blocking outbound HTTP calls via   httpx  or   aiohttp .  High connection concurrency with low individual request activity is expected.  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":167,"path":168,"dir":96,"title":169,"description":170,"keywords":171,"body":175},"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.",[172,173,174],"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":177,"path":178,"dir":179,"title":180,"description":181,"keywords":182,"body":189},"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.",[112,183,184,185,186,187,188],"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:                                               +------------------------+\n                                            |   Locust Load Runner   |\n                                            |   (Headless Step-Load) |\n                                            +-----------+------------+\n                                                        |\n                         +------------------------------+------------------------------+\n                         |                              |                              |\n                         v                              v                              v\n             [ Flavors 1 & 2: WSGI ]        [ Flavor 3: ASGI-Sync ]       [ Flavors 4, 5 & 6: ASGI ]\n             Hurricane WSGI Mode            Hurricane ASGI Mode           Hurricane ASGI Mode\n             (Single Thread vs Auto-Threads) Django sync_to_async          Clean Async Views (httpx)\n             Sync DB (psycopg pool)         Sync HTTP (requests)          (Single vs Auto vs DAB Async ORM)\n                         |                              |                              |\n                         +------------------------------+------------------------------+\n                                                        |\n                                                        v\n                                              +--------------------+\n                                              | PostgreSQL 17 (DB) |\n                                              | (Real Database)    |\n                                              +--------------------+\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.0rc2   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":191,"path":192,"dir":179,"title":193,"description":194,"keywords":195,"body":201},"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.",[196,197,198,199,200],"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 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":203,"path":204,"dir":179,"title":205,"description":206,"keywords":207,"body":213},"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.",[208,209,210,211,212],"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                                Is your application predominantly:\n                                           |\n                  +------------------------+------------------------+\n                  |                                                 |\n         [ Relational \u002F ORM Heavy ]                        [ External I\u002FO Heavy ]\n         (CRUD, CMS, Relational DB,                        (Microservices, API Gateways,\n          Admin, Heavy DTL Templates)                       Upstream Calls, Long-Polling)\n                  |                                                 |\n                  v                                                 v\n       +----------------------+                          +----------------------+\n       |  WSGI (Worker=Auto)  |                          |  ASGI (Worker=Auto)  |\n       |  - Highest DB Speed  |                          |  - Flat Tail Latency |\n       |  - Zero Thread Hops  |                          |  - Non-blocking I\u002FO  |\n       +----------------------+                          +----------------------+\n                  |                                                 |\n                  +------------------------+------------------------+\n                                           |\n                        [ Running on Kubernetes Pods (1-2 vCPUs) ]\n                        ASGI provides decisive socket resiliency\n                        preventing threadpool exhaustion under load\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     --mode=asgi   \\\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":215,"path":216,"dir":7,"title":217,"description":218,"keywords":219,"body":226},"content:data-privacy.md","\u002Fdata-privacy","Privacy Policy","Information on how personal data is handled on django-hurricane.io and related documentation.",[220,221,222,223,224,225],"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":228,"path":229,"dir":7,"title":230,"description":231,"keywords":232,"body":235},"content:legal-notice.md","\u002Flegal-notice","Legal Notice","Provider identification and legal notices for Django Hurricane.",[233,234],"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 .",1793188632493]