This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: axum-08-tokio-task-cancellation-backpressure-standard

Axum 0.8 Tokio Task Cancellation & Hyper Socket Disconnect Guardrail

Enforces strict cancellation safety, RAII-driven cleanup, and child task termination for Axum 0.8 handlers backed by Tokio and Hyper. Mandates explicit cancellation token trees and abort-on-drop semantics to eliminate orphaned background workers, zombie streaming connections, and database connection pool starvation when clients abruptly disconnect.

Prohibited Anti-Pattern: Spawning detached tokio::spawn workloads inside Axum handlers without CancellationToken or RAII abort guards

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Axum 0.8 Tokio Task Cancellation & Hyper Socket Disconnect Guardrail - Enforces strict cancellation safety, RAII-driven cleanup, and child task termination for Axum 0.8 handlers backed by Tokio and Hyper. Mandates explicit cancellation token trees and abort-on-drop semantics to eliminate orphaned background workers, zombie streaming connections, and database connection pool starvation when clients abruptly disconnect.
globs: src/**/*.rs
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/axum-08-tokio-task-cancellation-backpressure-standard"
---

# Axum 0.8 Tokio Task Cancellation & Hyper Socket Disconnect Guardrail

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Spawning detached tokio::spawn workloads inside Axum handlers without CancellationToken or RAII abort guards

## System Constraints
You are a Principal Systems Architect specializing in high-throughput Axum 0.8, Hyper 1.x, and Tokio async runtimes. Your mandate is to enforce absolute cancellation safety and prevent worker task leakage caused by client disconnection drops. In Rust async runtimes, when a remote HTTP client drops the connection, Hyper cancels the handler future by dropping it at the nearest `.await` point. Code located after that `.await` point will never execute, and any detached `tokio::spawn` calls will become orphan background zombies. You must rigorously reject unlinked task spawning, unbounded response channels, and procedural post-await cleanup blocks, replacing them with RAII Drop guards, `tokio_util::sync::CancellationToken`, and bounded backpressure pipelines.

## Strict Guidelines
- Engineers MUST ALWAYS link secondary asynchronous jobs spawned within a request lifecycle to a parent `tokio_util::sync::CancellationToken` or hold their `JoinHandle` inside an abort-on-drop wrapper (e.g., `AbortOnDropHandle`).
- Engineers MUST NOT place critical transactional rollback or resource cleanup logic procedurally after an `.await` boundary; all cleanup MUST be encapsulated within RAII `Drop` implementations.
- Code MUST NEVER invoke raw `tokio::spawn` for request-scoped operations without registering the handle with a request-scoped `tokio_util::task::TaskTracker` or passing a cooperative cancellation child token.
- Services streaming responses (Server-Sent Events, WebSocket frames, chunked bodies) MUST use bounded channels (`tokio::sync::mpsc::channel`) with backpressure monitoring to trigger termination immediately when Hyper detects a closed TCP socket.
- Handlers MUST ensure all operations spanning multiple `.await` points are strictly cancellation-safe; holding non-atomic transient state across yield points without idempotency protections is forbidden.

## Bad vs Good Implementations
### Unlinked Task Spawning and Post-Await Cleanup vs. RAII Guard and CancellationToken

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: When Hyper drops the future at `external_service_call.await` due to a client disconnect, `record_audit_log` is skipped, leaving system records out of sync. Furthermore, the `tokio::spawn` worker continues running in the background, consuming CPU and memory for a request that the client has already abandoned.
```rust
use axum::{extract::State, http::StatusCode, response::IntoResponse, Json};
use serde::Deserialize;
use std::sync::Arc;

#[derive(Deserialize)]
pub struct JobPayload { pub id: String, pub data: Vec<u8> }
pub struct AppState { pub db: sqlx::PgPool }

pub async fn process_job_handler(
    State(state): State<Arc<AppState>>,
    Json(payload): Json<JobPayload>,
) -> Result<impl IntoResponse, StatusCode> {
    // ANTI-PATTERN: Acquire resource manually before await
    let mut conn = state.db.acquire().await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    
    // ANTI-PATTERN: Detached task runs indefinitely if client disconnects during execution
    let payload_id = payload.id.clone();
    tokio::spawn(async move {
        heavy_computation_worker(payload_id).await;
    });

    let result = external_service_call(&payload.data).await
        .map_err(|_| StatusCode::BAD_GATEWAY)?;

    // CRITICAL BUG: If client drops connection during external_service_call,
    // execution aborts immediately. The code below NEVER runs, leaving
    // external state unfinalized or audit logs missing.
    record_audit_log(&mut conn, &payload.id, &result).await
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    Ok(StatusCode::OK)
}

async fn heavy_computation_worker(_id: String) {}
async fn external_service_call(_data: &[u8]) -> Result<String, ()> { Ok("done".into()) }
async fn record_audit_log(_conn: &mut sqlx::pool::PoolConnection<sqlx::Postgres>, _id: &str, _res: &str) -> Result<(), ()> { Ok(()) }
```

#### Production Standard (Correct)
> **Standard**: Wraps the background task in an `AbortOnDropHandle` linked to a `CancellationToken`, guaranteeing that if the client terminates the connection, the background worker is immediately aborted. Crucial teardown logic is encapsulated inside an RAII `InFlightGuard` whose `Drop` implementation executes reliably even when hyper drops the future.
```rust
use axum::{extract::State, http::StatusCode, response::IntoResponse, Json};
use serde::Deserialize;
use std::sync::Arc;
use tokio_util::sync::CancellationToken;
use tokio_util::task::AbortOnDropHandle;

#[derive(Deserialize)]
pub struct JobPayload { pub id: String, pub data: Vec<u8> }
pub struct AppState { pub db: sqlx::PgPool }

// Invariant: Cleanup and unfinalized state rollback encapsulated in RAII Drop
struct InFlightGuard<'a> {
    job_id: &'a str,
    completed: bool,
}

impl<'a> Drop for InFlightGuard<'a> {
    fn drop(&mut self) {
        if !self.completed {
            tracing::warn!(job_id = self.job_id, "Request future dropped prematurely; rolling back transient state");
            // Synchronous metric increment or channel dispatch for asynchronous rollback worker
        }
    }
}

pub async fn process_job_handler(
    State(state): State<Arc<AppState>>,
    Json(payload): Json<JobPayload>,
) -> Result<impl IntoResponse, StatusCode> {
    let mut guard = InFlightGuard { job_id: &payload.id, completed: false };
    let cancel_token = CancellationToken::new();
    let child_token = cancel_token.child_token();

    // INVARIANT: Spawned worker bound to AbortOnDropHandle and CancellationToken
    let payload_id = payload.id.clone();
    let _worker_handle = AbortOnDropHandle::new(tokio::spawn(async move {
        tokio::select! {
            _ = child_token.cancelled() => {
                tracing::info!(job_id = %payload_id, "Worker task cancelled by parent drop");
            }
            _ = heavy_computation_worker(payload_id) => {}
        }
    }));

    // If client disconnects here, guard is safely dropped and _worker_handle aborts the spawned task
    let result = external_service_call(&payload.data).await
        .map_err(|_| StatusCode::BAD_GATEWAY)?;

    let mut conn = state.db.acquire().await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    record_audit_log(&mut conn, &payload.id, &result).await
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    guard.completed = true;
    Ok(StatusCode::OK)
}

async fn heavy_computation_worker(_id: String) {}
async fn external_service_call(_data: &[u8]) -> Result<String, ()> { Ok("done".into()) }
async fn record_audit_log(_conn: &mut sqlx::pool::PoolConnection<sqlx::Postgres>, _id: &str, _res: &str) -> Result<(), ()> { Ok(()) }
```

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 Tokio Task Cancellation & Hyper Socket Disconnect Guardrail

Axum 0.8 Tokio Task Cancellation & Hyper Socket Disconnect Guardrail defines an industrial-grade behavioral standard for backend engineering. Enforces strict cancellation safety, RAII-driven cleanup, and child task termination for Axum 0.8 handlers backed by Tokio and Hyper. Mandates explicit cancellation token trees and abort-on-drop semantics to eliminate orphaned background workers, zombie streaming connections, and database connection pool starvation when clients abruptly disconnect. 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 detached tokio::spawn workloads inside Axum handlers without CancellationToken or RAII abort guards 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 detached tokio::spawn workloads inside Axum handlers without CancellationToken or RAII abort guardsCritical
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 link secondary asynchronous jobs spawned within a request lifecycle to a parent `tokio_util

Engineers MUST ALWAYS link secondary asynchronous jobs spawned within a request lifecycle to a parent `tokio_util::sync::CancellationToken` or hold their `JoinHandle` inside an abort-on-drop wrapper (e.g., `AbortOnDropHandle`).

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 place critical transactional rollback or resource cleanup logic procedurally after an `.await` boundary

Engineers MUST NOT place critical transactional rollback or resource cleanup logic procedurally after an `.await` boundary; all cleanup MUST be encapsulated within RAII `Drop` implementations.

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

Code MUST NEVER invoke raw `tokio

Code MUST NEVER invoke raw `tokio::spawn` for request-scoped operations without registering the handle with a request-scoped `tokio_util::task::TaskTracker` or passing a cooperative cancellation 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.
4

Services streaming responses (Server-Sent Events, WebSocket frames, chunked bodies) MUST use bounded channels (`tokio

Services streaming responses (Server-Sent Events, WebSocket frames, chunked bodies) MUST use bounded channels (`tokio::sync::mpsc::channel`) with backpressure monitoring to trigger termination immediately when Hyper detects a closed TCP socket.

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

Handlers MUST ensure all operations spanning multiple `.await` points are strictly cancellation-safe

Handlers MUST ensure all operations spanning multiple `.await` points are strictly cancellation-safe; holding non-atomic transient state across yield points without idempotency protections is forbidden.

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 Tokio Task Cancellation & Hyper Socket Disconnect Guardrail critical for AI coding assistants?

Enforces strict cancellation safety, RAII-driven cleanup, and child task termination for Axum 0.8 handlers backed by Tokio and Hyper. Mandates explicit cancellation token trees and abort-on-drop semantics to eliminate orphaned background workers, zombie streaming connections, and database connection pool starvation when clients abruptly disconnect. 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 detached tokio::spawn workloads inside Axum handlers without CancellationToken or RAII abort guards) 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