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

Axum 0.8 Hierarchical CancellationToken Graceful Drain Architecture

Enforces hierarchical Tokio CancellationToken pipelines in Axum 0.8 services to orchestrate deterministic teardown cascades across SSE connections and background tasks. Guarantees active streams emit protocol-compliant termination sequences and in-flight HTTP payloads complete cleanly before socket closure during rolling deployments.

Prohibited Anti-Pattern: Abrupt Process Termination and Orphaned SSE Streams During SIGTERM Cascades

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Axum 0.8 Hierarchical CancellationToken Graceful Drain Architecture - Enforces hierarchical Tokio CancellationToken pipelines in Axum 0.8 services to orchestrate deterministic teardown cascades across SSE connections and background tasks. Guarantees active streams emit protocol-compliant termination sequences and in-flight HTTP payloads complete cleanly before socket closure during rolling deployments.
globs: src/**/*.rs
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/axum-0-8-hierarchical-cancellation-token-graceful-drain"
---

# Axum 0.8 Hierarchical CancellationToken Graceful Drain Architecture

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Abrupt Process Termination and Orphaned SSE Streams During SIGTERM Cascades

## System Constraints
You are a Principal Rust Architect enforcing deterministic graceful drain pipelines in Axum 0.8 microservices. Mandate the use of tokio_util::sync::CancellationToken hierarchies to orchestrate phased shutdowns: signal root cancellation, notify child domains (SSE streams, queue workers), emit terminal stream framing, and await task set completion with bounded deadlines.

## Strict Guidelines
- Engineers MUST ALWAYS instantiate a root `CancellationToken` bound to OS shutdown signals (`SIGTERM`, `SIGINT`) and derive domain-specific child tokens via `root_token.child_token()`.
- Engineers MUST NOT rely exclusively on `axum::serve(...).with_graceful_shutdown()` without propagating child tokens to long-lived streams and detached `tokio::spawn` tasks.
- Services MUST wrap long-lived SSE (Server-Sent Events) streams with child cancellation listeners, cleanly emitting a terminal protocol event (e.g., `event: shutdown`) before terminating the stream.
- Background workers and detached tasks MUST be tracked using a `tokio::task::JoinSet` or bounded task tracker registered to the cancellation pipeline.
- Shutdown sequences MUST enforce a two-phase drain with bounded timeouts: Phase 1 cancels ingress and SSE child tokens; Phase 2 awaits in-flight workers via `JoinSet::join_next` within a hard deadline before forcing process exit.

## Bad vs Good Implementations
### Hierarchical Cancellation and SSE Drain in Axum 0.8

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Axum's built-in graceful shutdown stops accepting new connections and waits for standard HTTP handlers to complete, but it abruptly drops infinite SSE streams and untracked background tasks. Active SSE clients encounter hard connection resets without receiving terminal events, triggering thundering-herd reconnections during rolling deployments.
```rust
use axum::{routing::get, response::sse::{Event, Sse}, Router};
use tokio::signal;
use std::{convert::Infallible, time::Duration};
use tokio_stream::wrappers::IntervalStream;
use futures_util::StreamExt;

async fn sse_handler() -> Sse<impl futures_util::Stream<Item = Result<Event, Infallible>>> {
    // ANTI-PATTERN: Infinite stream with no cancellation integration.
    // Severing TCP abruptly causes client retry storms and lost state.
    let stream = IntervalStream::new(tokio::time::interval(Duration::from_secs(1)))
        .map(|_| Ok(Event::default().data("tick")));
    Sse::new(stream)
}

#[tokio::main]
async fn main() {
    let app = Router::new().route("/events", get(sse_handler));
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    
    // ANTI-PATTERN: Standard graceful shutdown drops detached tasks and severs active SSE sockets instantly
    axum::serve(listener, app)
        .with_graceful_shutdown(async { signal::ctrl_c().await.unwrap(); })
        .await
        .unwrap();
}
```

#### Production Standard (Correct)
> **Standard**: Uses a root CancellationToken and child tokens. When SIGTERM occurs, the SSE child token is canceled, allowing active streams to emit a structured 'shutdown' event before closing. The Axum server completes its drain without abruptly resetting TCP sockets.
```rust
use axum::{extract::State, response::sse::{Event, KeepAlive, Sse}, routing::get, Router};
use futures_util::stream::{self, Stream, StreamExt};
use std::{convert::Infallible, sync::Arc, time::Duration};
use tokio::signal;
use tokio_util::sync::CancellationToken;

#[derive(Clone)]
struct AppState {
    sse_token: CancellationToken,
}

async fn sse_handler(
    State(state): State<Arc<AppState>>,
) -> Sse<impl Stream<Item = Result<Event, Infallible>>> {
    let token = state.sse_token.child_token();
    let ticker = tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(Duration::from_secs(1)))
        .map(|_| Event::default().data("heartbeat"));

    // Transform stream to gracefully terminate when the child token fires
    let stream = async_stream::stream! {
        tokio::pin!(ticker);
        loop {
            tokio::select! {
                _ = token.cancelled() => {
                    yield Ok(Event::default().event("shutdown").data("node draining, reconnect to peer"));
                    break;
                }
                Some(item) = ticker.next() => {
                    yield Ok(item);
                }
            }
        }
    };

    Sse::new(stream).keep_alive(KeepAlive::default())
}

#[tokio::main]
async fn main() {
    let root_token = CancellationToken::new();
    let sse_token = root_token.child_token();
    let state = Arc::new(AppState { sse_token: sse_token.clone() });

    let app = Router::new().route("/events", get(sse_handler)).with_state(state);
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();

    let root_token_trigger = root_token.clone();
    tokio::spawn(async move {
        let ctrl_c = async { signal::ctrl_c().await.expect("failed to listen for ctrl_c"); };
        #[cfg(unix)]
        let terminate = async {
            signal::unix::signal(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 => {},
        }
        root_token_trigger.cancel();
    });

    let server_token = root_token.clone();
    axum::serve(listener, app)
        .with_graceful_shutdown(async move {
            server_token.cancelled().await;
            // Phase 1: Notify SSE clients to cleanly migrate before socket drain
            sse_token.cancel();
        })
        .await
        .unwrap();
}
```

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 Hierarchical CancellationToken Graceful Drain Architecture

Axum 0.8 Hierarchical CancellationToken Graceful Drain Architecture defines an industrial-grade behavioral standard for backend engineering. Enforces hierarchical Tokio CancellationToken pipelines in Axum 0.8 services to orchestrate deterministic teardown cascades across SSE connections and background tasks. Guarantees active streams emit protocol-compliant termination sequences and in-flight HTTP payloads complete cleanly before socket closure during rolling deployments. 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 Process Termination and Orphaned SSE Streams During SIGTERM Cascades 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 Process Termination and Orphaned SSE Streams During SIGTERM CascadesCritical
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 instantiate a root `CancellationToken` bound to OS shutdown signals (`SIGTERM`, `SIGINT`) and derive domain-specific child tokens via `root_token.child_token()`.

Engineers MUST ALWAYS instantiate a root `CancellationToken` bound to OS shutdown signals (`SIGTERM`, `SIGINT`) and derive domain-specific child tokens via `root_token.child_token()`.

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 rely exclusively on `axum

Engineers MUST NOT rely exclusively on `axum::serve(...).with_graceful_shutdown()` without propagating child tokens to long-lived streams and detached `tokio::spawn` 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.
3

Services MUST wrap long-lived SSE (Server-Sent Events) streams with child cancellation listeners, cleanly emitting a terminal protocol event (e.g., `event

Services MUST wrap long-lived SSE (Server-Sent Events) streams with child cancellation listeners, cleanly emitting a terminal protocol event (e.g., `event: shutdown`) before terminating the stream.

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

Background workers and detached tasks MUST be tracked using a `tokio

Background workers and detached tasks MUST be tracked using a `tokio::task::JoinSet` or bounded task tracker registered to the cancellation pipeline.

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

Shutdown sequences MUST enforce a two-phase drain with bounded timeouts

Shutdown sequences MUST enforce a two-phase drain with bounded timeouts: Phase 1 cancels ingress and SSE child tokens; Phase 2 awaits in-flight workers via `JoinSet::join_next` within a hard deadline before forcing process exit.

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 Hierarchical CancellationToken Graceful Drain Architecture critical for AI coding assistants?

Enforces hierarchical Tokio CancellationToken pipelines in Axum 0.8 services to orchestrate deterministic teardown cascades across SSE connections and background tasks. Guarantees active streams emit protocol-compliant termination sequences and in-flight HTTP payloads complete cleanly before socket closure during rolling deployments. 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 Process Termination and Orphaned SSE Streams During SIGTERM Cascades) 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