This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: axum-0-8-graceful-drain-coordination

Axum 0.8 Tower Service Graceful Drain and Transactional Lifetime Protocol

Mandates explicit in-flight task tracking and cooperative cancellation hierarchies during Axum 0.8 graceful shutdown. Ensures long-lived HTTP/3 streams, WebSocket connections, and Tower layered middleware drain completely before server drop without stranding active database sessions or dropping uncommitted state.

Prohibited Anti-Pattern: Dangling Async Tasks and Orphaned Transactions via Naive Axum Graceful Shutdown

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Axum 0.8 Tower Service Graceful Drain and Transactional Lifetime Protocol - Mandates explicit in-flight task tracking and cooperative cancellation hierarchies during Axum 0.8 graceful shutdown. Ensures long-lived HTTP/3 streams, WebSocket connections, and Tower layered middleware drain completely before server drop without stranding active database sessions or dropping uncommitted state.
globs: src/**/*.rs
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/axum-0-8-graceful-drain-coordination"
---

# Axum 0.8 Tower Service Graceful Drain and Transactional Lifetime Protocol

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Dangling Async Tasks and Orphaned Transactions via Naive Axum Graceful Shutdown

## System Constraints
You are a Principal Rust Architect enforcing deterministic graceful draining in Axum 0.8, Tower, and Tokio services. You must prevent orphaned database transactions and uncoordinated socket drops by mandating hierarchical cancellation tokens and TaskTracker instances across all WebSocket, HTTP/3, and long-polling connection lifecycles.

## Strict Guidelines
- Engineers MUST ALWAYS couple `axum::serve(...).with_graceful_shutdown(...)` with a `tokio_util::task::TaskTracker` and `tokio_util::sync::CancellationToken` to track and coordinate connection-bound background tasks.
- Engineers MUST NOT spawn detached tasks (`tokio::spawn`) inside WebSocket or stream handlers without passing tracked shutdown handles and active transactional guards.
- WebSocket handlers MUST listen for cancellation signals, send a standard WS Close Frame (code 1001 'Going Away') to connected clients, and wait for transmission completion prior to terminating the task.
- Transactional contexts within Tower middleware and service handlers MUST bind rollback guards to `Drop` implementations or monitor cooperative cancellation tokens before finalizing multi-step mutations.
- Services MUST wait on `tracker.wait().await` with an bounded drain timeout after the root server future resolves to ensure stubborn connections are explicitly severed without hanging the host process indefinitely.

## Bad vs Good Implementations
### Naive Spawn Without Task Tracker vs Structured Drain with CancellationToken

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Axum's with_graceful_shutdown only waits for the top-level HTTP connection futures to finish parsing; it has no visibility into detached tasks spawned via tokio::spawn. When main() terminates, long-lived WebSockets are aborted instantly, stranding active database transactions and skipping WS close handshakes.
```rust
use axum::{routing::get, Router, extract::ws::{WebSocketUpgrade, WebSocket}};
use tokio::net::TcpListener;

async fn ws_handler(ws: WebSocketUpgrade) -> axum::response::Response {
    ws.on_upgrade(|mut socket: WebSocket| async move {
        // ANTI-PATTERN: Detached task spawned with no coordination or shutdown awareness.
        // When graceful_shutdown fires, axum::serve stops accepting new connections
        // but this task is abruptly terminated when main exits, stranding the DB transaction.
        tokio::spawn(async move {
            let mut tx = begin_db_transaction().await;
            while let Some(Ok(msg)) = socket.recv().await {
                apply_mutation(&mut tx, msg).await;
            }
            tx.commit().await.unwrap();
        });
    })
}

pub async fn run_server() {
    let app = Router::new().route("/ws", get(ws_handler));
    let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app)
        .with_graceful_shutdown(shutdown_signal())
        .await
        .unwrap();
}
```

#### Production Standard (Correct)
> **Standard**: Tracks all asynchronous connection workers via TaskTracker and propagates a cooperative CancellationToken upon receiving the shutdown signal. Long-lived WebSockets send proper 1001 CloseFrames, roll back or commit transactional boundaries cleanly, and a bounded 15-second grace period guarantees non-hanging termination.
```rust
use axum::{routing::get, Router, extract::{ws::{WebSocketUpgrade, WebSocket, Message}, State}};
use axum::extract::ws::close_code;
use tokio::net::TcpListener;
use tokio_util::sync::CancellationToken;
use tokio_util::task::TaskTracker;
use std::time::Duration;
use std::sync::Arc;

#[derive(Clone)]
struct AppState {
    tracker: TaskTracker,
    token: CancellationToken,
}

async fn ws_handler(State(state): State<Arc<AppState>>, ws: WebSocketUpgrade) -> axum::response::Response {
    ws.on_upgrade(move |socket| handle_socket(socket, state))
}

async fn handle_socket(mut socket: WebSocket, state: Arc<AppState>) {
    let token = state.token.clone();
    // PROD INVARIANT: Register the long-lived task with TaskTracker
    state.tracker.spawn(async move {
        let mut tx = begin_db_transaction().await;
        loop {
            tokio::select! {
                biased;
                _ = token.cancelled() => {
                    // Graceful close: Send 1001 Going Away frame and rollback/flush
                    let close_frame = Message::Close(Some(axum::extract::ws::CloseFrame {
                        code: close_code::AWAY,
                        reason: "Server shutting down".into(),
                    }));
                    let _ = socket.send(close_frame).await;
                    let _ = tx.rollback().await;
                    break;
                }
                Some(Ok(msg)) = socket.recv() => {
                    apply_mutation(&mut tx, msg).await;
                }
                else => break,
            }
        }
    });
}

pub async fn run_server() {
    let tracker = TaskTracker::new();
    let token = CancellationToken::new();
    let state = Arc::new(AppState { tracker: tracker.clone(), token: token.clone() });
    let app = Router::new().route("/ws", get(ws_handler)).with_state(state);

    let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app)
        .with_graceful_shutdown(async move {
            shutdown_signal().await;
            token.cancel(); // Signal all active WS/HTTP-3 workers to drain
        })
        .await
        .unwrap();

    tracker.close();
    // Bounded timeout to prevent infinite hang from unresponsive clients
    tokio::select! {
        _ = tracker.wait() => {},
        _ = tokio::time::sleep(Duration::from_secs(15)) => {
            eprintln!("Drain timeout exceeded; forcing shutdown");
        }
    }
}
```

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 Tower Service Graceful Drain and Transactional Lifetime Protocol

Axum 0.8 Tower Service Graceful Drain and Transactional Lifetime Protocol defines an industrial-grade behavioral standard for backend engineering. Mandates explicit in-flight task tracking and cooperative cancellation hierarchies during Axum 0.8 graceful shutdown. Ensures long-lived HTTP/3 streams, WebSocket connections, and Tower layered middleware drain completely before server drop without stranding active database sessions or dropping uncommitted state. 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: Dangling Async Tasks and Orphaned Transactions via Naive Axum Graceful Shutdown 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 DriftDangling Async Tasks and Orphaned Transactions via Naive Axum Graceful ShutdownCritical
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 ALWAYS couple `axum

Engineers MUST ALWAYS couple `axum::serve(...).with_graceful_shutdown(...)` with a `tokio_util::task::TaskTracker` and `tokio_util::sync::CancellationToken` to track and coordinate connection-bound background tasks.

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 spawn detached tasks (`tokio

Engineers MUST NOT spawn detached tasks (`tokio::spawn`) inside WebSocket or stream handlers without passing tracked shutdown handles and active transactional guards.

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

WebSocket handlers MUST listen for cancellation signals, send a standard WS Close Frame (code 1001 'Going Away') to connected clients, and wait for transmission completion prior to terminating the task.

WebSocket handlers MUST listen for cancellation signals, send a standard WS Close Frame (code 1001 'Going Away') to connected clients, and wait for transmission completion prior to terminating the task.

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

Transactional contexts within Tower middleware and service handlers MUST bind rollback guards to `Drop` implementations or monitor cooperative cancellation tokens before finalizing multi-step mutations.

Transactional contexts within Tower middleware and service handlers MUST bind rollback guards to `Drop` implementations or monitor cooperative cancellation tokens before finalizing multi-step mutations.

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

Services MUST wait on `tracker.wait().await` with an bounded drain timeout after the root server future resolves to ensure stubborn connections are explicitly severed without hanging the host process indefinitely.

Services MUST wait on `tracker.wait().await` with an bounded drain timeout after the root server future resolves to ensure stubborn connections are explicitly severed without hanging the host process indefinitely.

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 Tower Service Graceful Drain and Transactional Lifetime Protocol critical for AI coding assistants?

Mandates explicit in-flight task tracking and cooperative cancellation hierarchies during Axum 0.8 graceful shutdown. Ensures long-lived HTTP/3 streams, WebSocket connections, and Tower layered middleware drain completely before server drop without stranding active database sessions or dropping uncommitted state. 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 (Dangling Async Tasks and Orphaned Transactions via Naive Axum Graceful Shutdown) 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