This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: axum-08-tower-per-tenant-lease-shedding

Axum 0.8 Per-Tenant Semaphore Lease & Deterministic Backpressure Load Shedding

Enforces deterministic bounded concurrency per tenant via Tower middleware lease acquisition prior to async handler buffer allocation. Prevents noisy-neighbor memory exhaustion and thread starvation by shedding excess requests with HTTP 429 before streaming request bodies into memory.

Prohibited Anti-Pattern: Buffering Request Payloads in Handlers Before Acquiring Tenant Concurrency Leases

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Axum 0.8 Per-Tenant Semaphore Lease & Deterministic Backpressure Load Shedding - Enforces deterministic bounded concurrency per tenant via Tower middleware lease acquisition prior to async handler buffer allocation. Prevents noisy-neighbor memory exhaustion and thread starvation by shedding excess requests with HTTP 429 before streaming request bodies into memory.
globs: src/**/*.rs, crates/**/*.rs
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/axum-08-tower-per-tenant-lease-shedding"
---

# Axum 0.8 Per-Tenant Semaphore Lease & Deterministic Backpressure Load Shedding

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Buffering Request Payloads in Handlers Before Acquiring Tenant Concurrency Leases

## System Constraints
You are a Principal Rust Architect enforcing multi-tenant concurrency isolation and backpressure in Axum 0.8 and Tower. Mandate deterministic per-tenant lease acquisition before any async request body deserialization or buffer allocation occurs.

## Strict Guidelines
- Engineers MUST acquire tenant-scoped concurrency permits via non-blocking lease checks (`try_acquire_owned`) within a Tower middleware layer before forwarding to the inner service.
- Engineers MUST NOT extract or buffer request payloads (`Json`, `Bytes`, `Multipart`) prior to successful tenant permit acquisition.
- Services MUST emit HTTP 429 (Too Many Requests) with a deterministic `Retry-After` header immediately upon permit acquisition failure.
- Components MUST store the acquired `OwnedSemaphorePermit` inside request extensions (`req.extensions_mut().insert(permit)`) to bind permit lifetime strictly to response completion.
- Tower services NEVER fall back to unbounded queues or heap-allocated async task spawns when per-tenant lease saturation occurs.

## Bad vs Good Implementations
### Naive Handler Body Allocation vs. Tower Per-Tenant Pre-Handler Lease Shedding

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The Json extractor allocates memory buffers for incoming requests before concurrency boundaries are checked, allowing malicious or runaway tenants to cause Out-Of-Memory (OOM) crashes through payload buffering.
```rust
use axum::{extract::Json, http::StatusCode, routing::post, Router};
use serde::Deserialize;

#[derive(Deserialize)]
struct LargePayload { data: Vec<u8> }

// ANTI-PATTERN: Request body is read and buffered into memory BEFORE tenant concurrency
// limits are evaluated. A single tenant saturating the server with 50MB payloads causes OOM.
async fn ingest_handler(Json(payload): Json<LargePayload>) -> Result<StatusCode, StatusCode> {
    // Tenant permit checked AFTER memory allocation
    if !tenant_has_capacity("tenant-123") {
        return Err(StatusCode::TOO_MANY_REQUESTS);
    }
    process(payload).await;
    Ok(StatusCode::OK)
}

pub fn app() -> Router {
    Router::new().route("/ingest", post(ingest_handler))
}
```

#### Production Standard (Correct)
> **Standard**: Acquires an RAII-bounded permit directly at the middleware layer using try_acquire_owned. Unpermitted requests are immediately shed with HTTP 429 without reading or allocating memory for the request body.
```rust
use axum::{body::Body, extract::Request, http::{header::RETRY_AFTER, HeaderValue, StatusCode}, middleware::Next, response::{IntoResponse, Response}};
use std::sync::Arc;
use tokio::sync::{OwnedSemaphorePermit, Semaphore};

#[derive(Clone)]
pub struct TenantLimiter {
    semaphore: Arc<Semaphore>,
}

// GUARDRAIL: Lease is acquired strictly BEFORE body consumption or downstream execution.
pub async fn tenant_lease_middleware(
    limiter: axum::extract::Extension<TenantLimiter>,
    mut req: Request<Body>,
    next: Next,
) -> Response {
    // Attempt immediate non-blocking lease acquisition
    match limiter.semaphore.clone().try_acquire_owned() {
        Ok(permit) => {
            // Retain permit in request extensions until the response stream terminates
            req.extensions_mut().insert(permit);
            next.run(req).await
        }
        Err(_) => {
            // Immediate backpressure shedding without streaming payload bytes
            let mut res = StatusCode::TOO_MANY_REQUESTS.into_response();
            res.headers_mut().insert(RETRY_AFTER, HeaderValue::from_static("1"));
            res
        }
    }
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Axum 0.8 Per-Tenant Semaphore Lease & Deterministic Backpressure Load Shedding

Axum 0.8 Per-Tenant Semaphore Lease & Deterministic Backpressure Load Shedding defines an industrial-grade behavioral standard for backend engineering. Enforces deterministic bounded concurrency per tenant via Tower middleware lease acquisition prior to async handler buffer allocation. Prevents noisy-neighbor memory exhaustion and thread starvation by shedding excess requests with HTTP 429 before streaming request bodies into memory. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Buffering Request Payloads in Handlers Before Acquiring Tenant Concurrency Leases Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftBuffering Request Payloads in Handlers Before Acquiring Tenant Concurrency LeasesCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST acquire tenant-scoped concurrency permits via non-blocking lease checks (`try_acquire_owned`) within a Tower middleware layer before forwarding to the inner service.

Engineers MUST acquire tenant-scoped concurrency permits via non-blocking lease checks (`try_acquire_owned`) within a Tower middleware layer before forwarding to the inner service.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT extract or buffer request payloads (`Json`, `Bytes`, `Multipart`) prior to successful tenant permit acquisition.

Engineers MUST NOT extract or buffer request payloads (`Json`, `Bytes`, `Multipart`) prior to successful tenant permit acquisition.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Services MUST emit HTTP 429 (Too Many Requests) with a deterministic `Retry-After` header immediately upon permit acquisition failure.

Services MUST emit HTTP 429 (Too Many Requests) with a deterministic `Retry-After` header immediately upon permit acquisition failure.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Components MUST store the acquired `OwnedSemaphorePermit` inside request extensions (`req.extensions_mut().insert(permit)`) to bind permit lifetime strictly to response completion.

Components MUST store the acquired `OwnedSemaphorePermit` inside request extensions (`req.extensions_mut().insert(permit)`) to bind permit lifetime strictly to response completion.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Tower services NEVER fall back to unbounded queues or heap-allocated async task spawns when per-tenant lease saturation occurs.

Tower services NEVER fall back to unbounded queues or heap-allocated async task spawns when per-tenant lease saturation occurs.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is Axum 0.8 Per-Tenant Semaphore Lease & Deterministic Backpressure Load Shedding critical for AI coding assistants?

Enforces deterministic bounded concurrency per tenant via Tower middleware lease acquisition prior to async handler buffer allocation. Prevents noisy-neighbor memory exhaustion and thread starvation by shedding excess requests with HTTP 429 before streaming request bodies into memory. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Buffering Request Payloads in Handlers Before Acquiring Tenant Concurrency Leases) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

Axum