This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: axum-graceful-draining-mpsc-backpressure

Axum Graceful Drain Synchronization with Bounded MPSC Channel Backpressure

Guarantees zero dropped in-flight HTTP requests and zero lost background buffer operations during Kubernetes rolling deployments. Synchronizes hyper/axum graceful listener termination (sending HTTP/2 GOAWAY frames and waiting for active transport sockets to close) with deterministic bounded Tokio MPSC channel closure, tracking active task references via CancellationToken and task trackers.

Prohibited Anti-Pattern: Abrupt Tokio Runtime Abort or Uncoordinated Channel Producer Drops Causing Dropped In-Flight Requests and 502 Bad Gateway / Broken Pipe Errors

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Axum Graceful Drain Synchronization with Bounded MPSC Channel Backpressure - Guarantees zero dropped in-flight HTTP requests and zero lost background buffer operations during Kubernetes rolling deployments. Synchronizes hyper/axum graceful listener termination (sending HTTP/2 GOAWAY frames and waiting for active transport sockets to close) with deterministic bounded Tokio MPSC channel closure, tracking active task references via CancellationToken and task trackers.
globs: src/**/*.rs, crates/**/*.rs
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/axum-graceful-draining-mpsc-backpressure"
---

# Axum Graceful Drain Synchronization with Bounded MPSC Channel Backpressure

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Abrupt Tokio Runtime Abort or Uncoordinated Channel Producer Drops Causing Dropped In-Flight Requests and 502 Bad Gateway / Broken Pipe Errors

## System Constraints
You are a Principal Systems Architect enforcing mission-critical reliability standards for Rust/Axum microservices running in Kubernetes. You must enforce deterministic graceful draining patterns where incoming traffic terminates via HTTP/2 GOAWAY frames, background tasks are bounded through Tokio MPSC backpressure, and consumer loops are fully drained prior to process termination.

## Strict Guidelines
- Services MUST implement a multi-stage shutdown sequence: (1) await SIGTERM/SIGINT, (2) stop accepting new ingress requests via axum::serve::with_graceful_shutdown, (3) drop upstream channel senders to signal EOF to background consumers, and (4) await background worker task completion with an overarching timeout.
- Engineers MUST ALWAYS use bounded channels (`tokio::sync::mpsc::channel(N)`) with explicit backpressure (`send().await`) to prevent unbounded memory growth during rolling updates.
- Engineers MUST NOT abort Tokio `JoinHandle` instances abruptly on shutdown signals; background worker loops MUST consume until `recv().await` returns `None`.
- Code MUST integrate `tokio_util::sync::CancellationToken` or `tokio_util::task::TaskTracker` to coordinate hierarchical lifecycle shutdown between Axum connection acceptors and asynchronous processing pipelines.
- HTTP/2 services MUST allow sufficient drain time for clients to observe initial `GOAWAY` frames and transition to alternate pods before tearing down underlying socket listeners.

## Bad vs Good Implementations
### Axum Bounded MPSC Drain Synchronization

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Using an unbounded channel risks OOM under load. When a shutdown signal occurs, `worker.abort()` abruptly terminates the consumer loop, dropping queued items already acknowledged to clients. Furthermore, `axum::serve` is cancelled mid-flight without allowing active HTTP/2 connections to finish in-flight requests or receive GOAWAY frames.
```rust
use axum::{routing::post, Router};
use tokio::sync::mpsc;

#[tokio::main]
async fn main() {
    // ANTI-PATTERN: Unbounded channel and instant task abortion on SIGTERM
    let (tx, mut rx) = mpsc::unbounded_channel::<String>();

    let worker = tokio::spawn(async move {
        while let Some(msg) = rx.recv().await {
            tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
            println!("Processed: {msg}");
        }
    });

    let app = Router::new().route("/enqueue", post(move |body: String| {
        let tx = tx.clone();
        async move {
            let _ = tx.send(body);
            "OK"
        }
    }));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    
    // Drops remaining channel messages and aborts worker immediately on SIGTERM
    tokio::select! {
        _ = axum::serve(listener, app) => {},
        _ = tokio::signal::ctrl_c() => {
            worker.abort(); // In-flight tasks in rx are discarded immediately
        }
    };
}
```

#### Production Standard (Correct)
> **Standard**: Uses bounded MPSC channel with backpressure. On SIGTERM, `axum::serve::with_graceful_shutdown` stops accepting new requests and waits for ongoing HTTP requests to complete. As routes finish, all `Sender` instances are dropped, causing `rx.recv()` to cleanly yield `None`. `TaskTracker` guarantees the application only exits after the queue is completely drained or the deadman timeout elapses.
```rust
use axum::{routing::post, Router, Extension};
use tokio::sync::mpsc;
use tokio_util::task::TaskTracker;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    const CHANNEL_CAPACITY: usize = 1024;
    let (tx, mut rx) = mpsc::channel::<String>(CHANNEL_CAPACITY);
    let tracker = TaskTracker::new();

    // Spawn worker under TaskTracker
    let worker_tracker = tracker.clone();
    tracker.spawn(async move {
        // rx.recv() returns None only after ALL senders are dropped
        while let Some(msg) = rx.recv().await {
            // Process remaining queued items sequentially or bounded-concurrently
            tokio::time::sleep(Duration::from_millis(50)).await;
            tracing::info!(message = %msg, "Processed item");
        }
        tracing::info!("Worker queue drained completely");
    });

    let app = Router::new()
        .route("/enqueue", post(|Extension(tx): Extension<mpsc::Sender<String>>, body: String| async move {
            tx.send(body).await.map_err(|_| axum::http::StatusCode::SERVICE_UNAVAILABLE)?;
            Ok::<&'static str, axum::http::StatusCode>("Enqueued")
        }))
        .layer(Extension(tx.clone()));

    // Explicitly drop original `tx` so only router extensions hold sender clones
    drop(tx);

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
    
    // Stage 1: Run server until shutdown signal triggers
    axum::serve(listener, app)
        .with_graceful_shutdown(shutdown_signal())
        .await?;

    // Stage 2: Stop accepting new tasks in tracker and close producer references
    tracing::info!("HTTP server drained; initiating MPSC queue drain");
    tracker.close();

    // Stage 3: Await full worker drain with strict timeout
    tokio::select! {
        _ = tracker.wait() => tracing::info!("All background workers completed gracefully"),
        _ = tokio::time::sleep(Duration::from_secs(30)) => {
            tracing::error!("Worker drain timed out, forcing shutdown");
        }
    }

    Ok(())
}

async fn shutdown_signal() {
    let ctrl_c = async {
        tokio::signal::ctrl_c().await.expect("Failed to install Ctrl+C handler");
    };

    #[cfg(unix)]
    let terminate = async {
        tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
            .expect("Failed to install SIGTERM handler")
            .recv()
            .await;
    };

    #[cfg(not(unix))]
    let terminate = std::future::pending::<()>();

    tokio::select! {
        _ = ctrl_c => {},
        _ = terminate => {},
    }
}
```

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 Graceful Drain Synchronization with Bounded MPSC Channel Backpressure

Axum Graceful Drain Synchronization with Bounded MPSC Channel Backpressure defines an industrial-grade behavioral standard for backend engineering. Guarantees zero dropped in-flight HTTP requests and zero lost background buffer operations during Kubernetes rolling deployments. Synchronizes hyper/axum graceful listener termination (sending HTTP/2 GOAWAY frames and waiting for active transport sockets to close) with deterministic bounded Tokio MPSC channel closure, tracking active task references via CancellationToken and task trackers. 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: Abrupt Tokio Runtime Abort or Uncoordinated Channel Producer Drops Causing Dropped In-Flight Requests and 502 Bad Gateway / Broken Pipe Errors 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 DriftAbrupt Tokio Runtime Abort or Uncoordinated Channel Producer Drops Causing Dropped In-Flight Requests and 502 Bad Gateway / Broken Pipe ErrorsCritical
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

Services MUST implement a multi-stage shutdown sequence

Services MUST implement a multi-stage shutdown sequence: (1) await SIGTERM/SIGINT, (2) stop accepting new ingress requests via axum::serve::with_graceful_shutdown, (3) drop upstream channel senders to signal EOF to background consumers, and (4) await background worker task completion with an overarching timeout.

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 ALWAYS use bounded channels (`tokio

Engineers MUST ALWAYS use bounded channels (`tokio::sync::mpsc::channel(N)`) with explicit backpressure (`send().await`) to prevent unbounded memory growth during rolling updates.

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

Engineers MUST NOT abort Tokio `JoinHandle` instances abruptly on shutdown signals

Engineers MUST NOT abort Tokio `JoinHandle` instances abruptly on shutdown signals; background worker loops MUST consume until `recv().await` returns `None`.

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

Code MUST integrate `tokio_util

Code MUST integrate `tokio_util::sync::CancellationToken` or `tokio_util::task::TaskTracker` to coordinate hierarchical lifecycle shutdown between Axum connection acceptors and asynchronous processing pipelines.

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

HTTP/2 services MUST allow sufficient drain time for clients to observe initial `GOAWAY` frames and transition to alternate pods before tearing down underlying socket listeners.

HTTP/2 services MUST allow sufficient drain time for clients to observe initial `GOAWAY` frames and transition to alternate pods before tearing down underlying socket listeners.

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 Graceful Drain Synchronization with Bounded MPSC Channel Backpressure critical for AI coding assistants?

Guarantees zero dropped in-flight HTTP requests and zero lost background buffer operations during Kubernetes rolling deployments. Synchronizes hyper/axum graceful listener termination (sending HTTP/2 GOAWAY frames and waiting for active transport sockets to close) with deterministic bounded Tokio MPSC channel closure, tracking active task references via CancellationToken and task trackers. 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 (Abrupt Tokio Runtime Abort or Uncoordinated Channel Producer Drops Causing Dropped In-Flight Requests and 502 Bad Gateway / Broken Pipe Errors) 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