[{"data":1,"prerenderedAt":195},["ShallowReactive",2],{"search-api":3},[4,17,29,39,51,61,72,90,103,114,123,133,142,151,163,173,186],{"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, custom Prometheus metrics, and remote debugging.",[35,36,37],"Custom Health Checks","Custom Prometheus Metrics","Remote Debugging in Kubernetes","  Developer Guide  Extend Hurricane with custom application health checks, business metrics, and remote debugging tools.   Custom Health Checks  Hurricane integrates directly with Django's native   System Check Framework . You can register custom checks that run during   \u002Falive  and   \u002Fready  probes.  1. Readiness Checks (  tags=[\"readiness\"] )  Readiness checks evaluate whether external dependencies (Redis, Celery brokers, 3rd party APIs) are operational:     from   django.core.checks   import   Error, register, Tags\n   import   redis\n   \n   \n   @register  (  \"readiness\"  )\n   def   check_redis_connection  (app_configs,   **  kwargs):\n       errors   =   []\n       try  :\n           client   =   redis.Redis(  host  =  \"redis-service\"  ,   port  =  6379  ,   socket_timeout  =  1.0  )\n           client.ping()\n       except   Exception   as   e:\n           errors.append(\n               Error(\n                   f  \"Redis service unreachable:   {  e  }  \"  ,\n                   hint  =  \"Verify Redis service connectivity in the cluster.\"  ,\n                   id  =  \"myapp.E001\"  ,\n               )\n           )\n       return   errors\n  If   check_redis_connection  returns an   Error ,   \u002Fready  responds with   500 Internal Server Error , and Kubernetes temporarily sheds traffic from the pod until Redis recovers.  2. Liveness Checks (  tags=[\"liveness\"] )  Liveness checks evaluate internal process health:     from   django.core.checks   import   Error, register\n   \n   \n   @register  (  \"liveness\"  )\n   def   check_internal_worker  (app_configs,   **  kwargs):\n       errors   =   []\n       # Verify internal worker threads or queue states\n       return   errors\n   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, Granian'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, Granian 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\u002FGranian gateway. 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":60},"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.",[56,57,58,59],"The 5 Metric Primitives","Developing Custom Metrics: Step-by-Step","Prometheus Scrape Verification","Prometheus Kubernetes Scrape Configuration","  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 and business metrics.   The 5 Metric Primitives  Hurricane provides five base metric primitives in   hurricane.metrics :     Metric Class  Type  When to Use  Update Mechanism      CounterMetric  Counter  Events that only increase (e.g. signups, failed logins, orders placed).   MyCounter.increment(amount=1)     StoredMetric  Gauge  Values that fluctuate over time (e.g. active users, cache size, worker count).   MyGauge.set(value)     CalculatedMetric  Gauge \u002F Computed  Values computed on-demand when   \u002Fmetrics  is scraped (e.g. DB counts).  Computes inside   get_value(*args)     AverageMetric  Summary \u002F Average  Running arithmetic mean updated per request (e.g. basket value, cart size).   MyAverage.add_value(val)     ObservedMetric  Histogram  Latency distributions and percentile buckets (e.g. payment gateway latency).   MyHistogram.observe(val)   Developing Custom Metrics: Step-by-Step  1. Define Metrics in Your Application  Create a   metrics.py  file inside your Django app:     from   prometheus_client   import   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\n   \n   \n   # 1. Counter: Tracks completed checkouts\n   class   CheckoutCounterMetric  (  CounterMetric  ):\n       code   =   \"ecommerce_checkouts_total\"\n       description   =   \"Total number of completed checkout operations\"\n   \n   \n   # 2. Stored Metric: Gauge of active connected users\n   class   ActiveSessionsMetric  (  StoredMetric  ):\n       code   =   \"ecommerce_active_sessions\"\n       description   =   \"Current number of active authenticated user sessions\"\n   \n   \n   # 3. Calculated Metric: Computes pending orders directly on scrape\n   class   PendingOrdersMetric  (  CalculatedMetric  ):\n       code   =   \"ecommerce_pending_orders_count\"\n       description   =   \"Number of orders currently in pending status\"\n   \n       @  classmethod\n       def   get_value  (cls,   *  args):\n           # Executes automatically only when Prometheus scrapes \u002Fmetrics\n           return   Order.objects.filter(  status  =  \"pending\"  ).count()\n   \n   \n   # 4. Average Metric: Running moving average of order values\n   class   AverageOrderValueMetric  (  AverageMetric  ):\n       code   =   \"ecommerce_order_value_average_dollars\"\n       description   =   \"Average transaction dollar amount per completed order\"\n   \n   \n   # 5. Observed Metric: Latency histogram for external payment gateway\n   class   PaymentGatewayLatencyMetric  (  ObservedMetric  ):\n       code   =   \"ecommerce_payment_gateway_latency_seconds\"\n       description   =   \"Latency distribution of third-party payment provider calls\"\n       prometheus   =   Histogram(\n           \"ecommerce_payment_gateway_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   # Register all custom metrics with Hurricane's registry\n   registry.register(CheckoutCounterMetric)\n   registry.register(ActiveSessionsMetric)\n   registry.register(PendingOrdersMetric)\n   registry.register(AverageOrderValueMetric)\n   registry.register(PaymentGatewayLatencyMetric)\n   2. Updating Metrics in Views and Services  Call your metrics directly within your Django views, services, or background workers:     import   time\n   from   django.http   import   JsonResponse\n   from   myapp.metrics   import   (\n       AverageOrderValueMetric,\n       CheckoutCounterMetric,\n       PaymentGatewayLatencyMetric,\n   )\n   from   myapp.services   import   charge_payment_provider\n   \n   \n   def   checkout_view  (request):\n       order_total   =   float  (request.  POST  .get(  \"total\"  ,   0.0  ))\n   \n       # Time external payment provider call\n       start_time   =   time.perf_counter()\n       charge_payment_provider(order_total)\n       duration   =   time.perf_counter()   -   start_time\n   \n       # Record metrics\n       CheckoutCounterMetric.increment()\n       AverageOrderValueMetric.add_value(order_total)\n       PaymentGatewayLatencyMetric.observe(duration)\n   \n       return   JsonResponse({  \"status\"  :   \"success\"  })\n   3. Hooking into Django Signals  Update stored metrics dynamically upon model changes using Django signals:     from   django.contrib.auth.signals   import   user_logged_in, user_logged_out\n   from   django.dispatch   import   receiver\n   from   myapp.metrics   import   ActiveSessionsMetric\n   \n   # Maintain active session count\n   _active_users   =   0\n   \n   \n   @receiver  (user_logged_in)\n   def   on_user_logged_in  (sender, request, user,   **  kwargs):\n       global   _active_users\n       _active_users   +=   1\n       ActiveSessionsMetric.set(_active_users)\n   \n   \n   @receiver  (user_logged_out)\n   def   on_user_logged_out  (sender, request, user,   **  kwargs):\n       global   _active_users\n       _active_users   =   max  (  0  , _active_users   -   1  )\n       ActiveSessionsMetric.set(_active_users)\n   Prometheus Scrape Verification  Once registered, your metrics appear automatically on the   \u002Fmetrics  endpoint:     curl   -s   http:\u002F\u002F127.0.0.1:8001\u002Fmetrics   |   grep   ecommerce\n   Output:     # HELP ecommerce_checkouts_total Total number of completed checkout operations\n   # TYPE ecommerce_checkouts_total counter\n   ecommerce_checkouts_total 42.0\n   \n   # HELP ecommerce_active_sessions Current number of active authenticated user sessions\n   # TYPE ecommerce_active_sessions gauge\n   ecommerce_active_sessions 18.0\n   \n   # HELP ecommerce_pending_orders_count Number of orders currently in pending status\n   # TYPE ecommerce_pending_orders_count gauge\n   ecommerce_pending_orders_count 3.0\n   \n   # HELP ecommerce_order_value_average_dollars Average transaction dollar amount per completed order\n   # TYPE ecommerce_order_value_average_dollars gauge\n   ecommerce_order_value_average_dollars 64.50\n   \n   # HELP ecommerce_payment_gateway_latency_seconds Payment gateway latency in seconds\n   # TYPE ecommerce_payment_gateway_latency_seconds histogram\n   ecommerce_payment_gateway_latency_seconds_bucket{le=\"0.1\"} 35.0\n   ecommerce_payment_gateway_latency_seconds_bucket{le=\"0.5\"} 41.0\n   ecommerce_payment_gateway_latency_seconds_bucket{le=\"1.0\"} 42.0\n   ecommerce_payment_gateway_latency_seconds_bucket{le=\"+Inf\"} 42.0\n   ecommerce_payment_gateway_latency_seconds_count 42.0\n   ecommerce_payment_gateway_latency_seconds_sum 4.82\n   Prometheus Kubernetes Scrape Configuration  To collect metrics in a Kubernetes cluster, configure Prometheus to scrape the dedicated probe port (  8001 ):     apiVersion  :   monitoring.coreos.com\u002Fv1\n   kind  :   PodMonitor\n   metadata  :\n     name  :   django-hurricane-monitor\n     labels  :\n       release  :   prometheus-stack\n   spec  :\n     selector  :\n       matchLabels  :\n         app  :   django-app\n     podMetricsEndpoints  :\n     -   port  :   probes\n       path  :   \u002Fmetrics\n       interval  :   15s\n       scrapeTimeout  :   10s\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":62,"path":63,"dir":20,"title":64,"description":65,"keywords":66,"body":71},"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.",[67,68,69,70],"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":73,"path":74,"dir":75,"title":76,"description":77,"keywords":78,"body":89},"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.",[79,80,81,82,83,84,85,86,87,88],"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 Granian. In ASGI mode, defaults to the number of available CPU cores (capped at 16) to allow multi-core event loop task scheduling. In WSGI mode, defaults to 1.  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":91,"path":92,"dir":93,"title":94,"description":95,"keywords":96,"body":102},"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.",[97,98,99,100,101],"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 ).  System 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":104,"path":105,"dir":93,"title":106,"description":107,"keywords":108,"body":113},"content:3.concepts:2.rust-engine.md","\u002Fconcepts\u002Frust-engine","Rust-Powered Engine","How Granian, Rust Hyper, and Tokio power Hurricane's zero-copy asynchronous HTTP runtime.",[109,110,111,112],"Architecture Overview","Why Rust Over Python Event Loops?","Zero-Config WSGI & ASGI Auto-Detection","⚡ Comparative Benchmarks: Tornado vs. Granian","  Rust-Powered Engine  Hurricane 2.0 replaced Tornado's Python asyncio event loop with    Granian , a lightning-fast HTTP server built directly on Rust’s   Hyper  and   Tokio  runtimes.   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\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[Granian Native Rust WSGI Worker]\n           ProtocolSplit -->|ASGI_APPLICATION| ASGI[Granian 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 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, Granian's   WSGIWorker  manages OS worker threads directly from Rust, 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 Granian]\n       InitWSGI --> Serve\n    Classic Django Projects:  If   WSGI_APPLICATION = \"myproject.wsgi.application\"  is present, Hurricane boots with Granian's multithreaded WSGI engine.   Async & Channels Projects:  If   ASGI_APPLICATION = \"myproject.asgi.application\"  is configured, Hurricane automatically runs with Granian's asynchronous ASGI engine.   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: Tornado vs. Granian  We pit the classic Tornado-based Hurricane against the new Granian-powered engine using Locust under identical high-concurrency conditions:     Metric  Tornado Baseline  Granian (New 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, Tornado mistook pending asyncio task counts for saturated request backlogs, triggering 160 false unready events that pulled pods out of service endpoints. Granian 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":115,"path":116,"dir":93,"title":117,"description":118,"keywords":119,"body":122},"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.",[120,121],"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":124,"path":125,"dir":93,"title":126,"description":127,"keywords":128,"body":132},"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.",[129,130,131],"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":134,"path":135,"dir":93,"title":136,"description":137,"keywords":138,"body":141},"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.",[139,140],"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":143,"path":144,"dir":93,"title":145,"description":146,"keywords":147,"body":150},"content:3.concepts:6.webhooks.md","\u002Fconcepts\u002Fwebhooks","Lifecycle Webhooks","Asynchronous HTTP notifications for pod lifecycle state changes and health transitions.",[148,149],"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":152,"path":153,"dir":93,"title":154,"description":155,"keywords":156,"body":162},"content:3.concepts:7.asgi-vs-wsgi.md","\u002Fconcepts\u002Fasgi-vs-wsgi","ASGI vs. WSGI Architecture","Understand the concurrency models, Granian execution layers, and readiness probe differences between ASGI and WSGI deployments.",[157,158,159,160,161],"Architecture Comparison","Concurrency Models under Granian","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 underlying Rust-powered   Granian  engine.  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 )   Concurrency Models under Granian  Granian manages concurrency through three distinct layers:     graph TD\n       Client[Incoming Client Requests] --> RustCore[Granian Rust Hyper\u002FTokio Core]\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 Granian's   blocking_threads  pool.  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.  Granian's   --runtime-threads  automatically defaults to the number of available CPU cores (up to 16) in ASGI mode, allowing the 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), Granian'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, ASGI leverages Granian's 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":164,"path":165,"dir":93,"title":166,"description":167,"keywords":168,"body":172},"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.",[169,170,171],"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 (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 Granian's unified Rust core 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":174,"path":175,"dir":7,"title":176,"description":177,"keywords":178,"body":185},"content:data-privacy.md","\u002Fdata-privacy","Privacy Policy","Information on how personal data is handled on django-hurricane.io and related documentation.",[179,180,181,182,183,184],"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":187,"path":188,"dir":7,"title":189,"description":190,"keywords":191,"body":194},"content:legal-notice.md","\u002Flegal-notice","Legal Notice","Provider identification and legal notices for Django Hurricane.",[192,193],"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 .",1792748333304]