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

Axum 0.8 Graceful WebSocket Drain-Fencing Standard

Enforces deterministic drain-fencing and cooperative task teardown for bi-directional WebSocket streams in Axum 0.8 during cluster rollouts. Prevents dropped frames, dangling Tokio tasks, and broker desynchronization by decoupling socket upgrades from unmonitored runtime tasks using tokio_util::task::TaskTracker and broadcast cancellation tokens.

Prohibited Anti-Pattern: Spawning Unfenced Tokio Tasks for WebSocket Upgrades Without Cooperative Drain Propagation

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Axum 0.8 Graceful WebSocket Drain-Fencing Standard - Enforces deterministic drain-fencing and cooperative task teardown for bi-directional WebSocket streams in Axum 0.8 during cluster rollouts. Prevents dropped frames, dangling Tokio tasks, and broker desynchronization by decoupling socket upgrades from unmonitored runtime tasks using tokio_util::task::TaskTracker and broadcast cancellation tokens.
globs: src/**/*.rs
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/axum-0-8-graceful-websocket-drain-fencing"
---

# Axum 0.8 Graceful WebSocket Drain-Fencing Standard

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Spawning Unfenced Tokio Tasks for WebSocket Upgrades Without Cooperative Drain Propagation

## System Constraints
You are a Principal Rust Systems Architect enforcing the Axum 0.8 Graceful WebSocket Drain-Fencing Standard. You mandate that no WebSocket upgrade handler spawns unmonitored Tokio tasks. All bi-directional stream loops must bind to a shared `tokio_util::sync::CancellationToken` and register against an orchestrated `tokio_util::task::TaskTracker`. When SIGTERM/SIGINT is received, the server must stop accepting incoming handshakes, notify existing clients via WebSocket Close frames (Code 1001 Going Away), flush pending outbound buffers with a strict deadline, and cleanly await task termination before the Tokio runtime exits.

## Strict Guidelines
- Engineers MUST ALWAYS track every spawned WebSocket connection task using `tokio_util::task::TaskTracker`.
- Engineers MUST ALWAYS pass a child or cloned `tokio_util::sync::CancellationToken` to every bi-directional streaming split loop (`Stream` / `Sink`).
- Engineers MUST NOT invoke `tokio::spawn` inside Axum `WebSocketUpgrade::on_upgrade` without registering the future in the application's drain fence.
- Code SHOULD explicitly transmit a WebSocket `Message::Close` frame with code `1001` (Going Away) upon receiving a cancellation signal prior to dropping the sink.
- Services MUST enforce a bounded drain timeout on the `TaskTracker::wait()` call in the top-level graceful shutdown future to prevent indefinitely hung connections.

## Bad vs Good Implementations
### Unmonitored Fire-and-Forget WebSocket Task vs. Drain-Fenced Tracker with Cooperative Close

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Spawning an unmonitored task via `tokio::spawn` without tying it to Axum's graceful shutdown lifecycle leaves the task orphaned. When the process terminates on SIGTERM, running futures are dropped instantly, corrupting in-flight state and dropping TCP sockets without standard WebSocket close frames.
```rust
use axum::{extract::ws::{WebSocket, WebSocketUpgrade}, response::IntoResponse};

pub async fn ws_handler(ws: WebSocketUpgrade) -> impl IntoResponse {
    // ANTI-PATTERN: Fire-and-forget task spawn without tracking or cancellation hook.
    // During zero-downtime deploy (SIGTERM), Axum terminates, aborting this task mid-flight.
    // The client encounters a hard TCP RST instead of a clean WS close handshake.
    ws.on_upgrade(|socket| async move {
        tokio::spawn(async move {
            let (mut sender, mut receiver) = socket.split();
            while let Some(Ok(msg)) = receiver.next().await {
                // Processing loop orphaned on rollout
                let _ = sender.send(msg).await;
            }
        });
    })
}
```

#### Production Standard (Correct)
> **Standard**: The socket task is registered into `TaskTracker` and listens for shutdown via `CancellationToken`. Upon receiving the drain signal, it emits a standard 1001 Close frame, flushes the sink with a deadline, and gracefully unwinds, enabling clean zero-downtime rollouts.
```rust
use axum::{extract::{ws::{Message, WebSocket, WebSocketUpgrade}, State}, response::IntoResponse};
use futures_util::{SinkExt, StreamExt};
use std::{sync::Arc, time::Duration};
use tokio_util::{sync::CancellationToken, task::TaskTracker};

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

pub async fn ws_handler(ws: WebSocketUpgrade, State(state): State<Arc<AppState>>) -> impl IntoResponse {
    ws.on_upgrade(move |socket| {
        let tracker = state.tracker.clone();
        let token = state.token.child_token();
        async move {
            tracker.spawn(async move {
                handle_socket(socket, token).await;
            });
        }
    })
}

async fn handle_socket(socket: WebSocket, token: CancellationToken) {
    let (mut sender, mut receiver) = socket.split();
    loop {
        tokio::select! {
            biased;
            _ = token.cancelled() => {
                // Cooperative drain: send Close frame (1001 Going Away) and flush
                let close_frame = Message::Close(Some(axum::extract::ws::CloseFrame {
                    code: 1001,
                    reason: "server_shutdown".into(),
                }));
                let _ = tokio::time::timeout(Duration::from_secs(3), async {
                    let _ = sender.send(close_frame).await;
                    let _ = sender.flush().await;
                }).await;
                break;
            }
            msg = receiver.next() => {
                match msg {
                    Some(Ok(Message::Close(_))) | None => break,
                    Some(Ok(m)) => { if sender.send(m).await.is_err() { break; } }
                    Some(Err(_)) => break,
                }
            }
        }
    }
}
```

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 Graceful WebSocket Drain-Fencing Standard

Axum 0.8 Graceful WebSocket Drain-Fencing Standard defines an industrial-grade behavioral standard for backend engineering. Enforces deterministic drain-fencing and cooperative task teardown for bi-directional WebSocket streams in Axum 0.8 during cluster rollouts. Prevents dropped frames, dangling Tokio tasks, and broker desynchronization by decoupling socket upgrades from unmonitored runtime tasks using tokio_util::task::TaskTracker and broadcast cancellation tokens. 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: Spawning Unfenced Tokio Tasks for WebSocket Upgrades Without Cooperative Drain Propagation 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 DriftSpawning Unfenced Tokio Tasks for WebSocket Upgrades Without Cooperative Drain PropagationCritical
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 track every spawned WebSocket connection task using `tokio_util

Engineers MUST ALWAYS track every spawned WebSocket connection task using `tokio_util::task::TaskTracker`.

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 pass a child or cloned `tokio_util

Engineers MUST ALWAYS pass a child or cloned `tokio_util::sync::CancellationToken` to every bi-directional streaming split loop (`Stream` / `Sink`).

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 invoke `tokio

Engineers MUST NOT invoke `tokio::spawn` inside Axum `WebSocketUpgrade::on_upgrade` without registering the future in the application's drain fence.

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 SHOULD explicitly transmit a WebSocket `Message

Code SHOULD explicitly transmit a WebSocket `Message::Close` frame with code `1001` (Going Away) upon receiving a cancellation signal prior to dropping the sink.

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 enforce a bounded drain timeout on the `TaskTracker

Services MUST enforce a bounded drain timeout on the `TaskTracker::wait()` call in the top-level graceful shutdown future to prevent indefinitely hung connections.

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 Graceful WebSocket Drain-Fencing Standard critical for AI coding assistants?

Enforces deterministic drain-fencing and cooperative task teardown for bi-directional WebSocket streams in Axum 0.8 during cluster rollouts. Prevents dropped frames, dangling Tokio tasks, and broker desynchronization by decoupling socket upgrades from unmonitored runtime tasks using tokio_util::task::TaskTracker and broadcast cancellation tokens. 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 (Spawning Unfenced Tokio Tasks for WebSocket Upgrades Without Cooperative Drain Propagation) 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