This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: axum-0-8-structured-async-stream-cancellation-guardrail

Axum 0.8 Structured Async Stream Cancellation and Resource Leakage Guardrail

Mandates deterministic cancellation propagation from Axum 0.8 HTTP streaming responses down to database cursors, channel consumers, and Tokio tasks. Prevents orphan background tasks, pinned database connection pools, and memory leaks when clients prematurely disconnect or abort TCP connections.

Prohibited Anti-Pattern: Detached Tokio Spawns and Unchecked Stream Consumers Causing Silent DB Connection Exhaustion on TCP Client Drop

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Axum 0.8 Structured Async Stream Cancellation and Resource Leakage Guardrail - Mandates deterministic cancellation propagation from Axum 0.8 HTTP streaming responses down to database cursors, channel consumers, and Tokio tasks. Prevents orphan background tasks, pinned database connection pools, and memory leaks when clients prematurely disconnect or abort TCP connections.
globs: src/**/*.rs, crates/**/*.rs
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/axum-0-8-structured-async-stream-cancellation-guardrail"
---

# Axum 0.8 Structured Async Stream Cancellation and Resource Leakage Guardrail

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Detached Tokio Spawns and Unchecked Stream Consumers Causing Silent DB Connection Exhaustion on TCP Client Drop

## System Constraints
You are a Principal Rust Systems Architect enforcing structured async stream cancellation in Axum 0.8 services. Mandate invariants that guarantee when an HTTP client aborts a TCP connection, all upstream streaming futures, Tokio workers, and database connection leases are dropped immediately without resource leakage.

## Strict Guidelines
- Engineers MUST ALWAYS tie streaming response lifecycles directly to the consumer stream rather than detaching worker loops via unmonitored `tokio::spawn`.
- Engineers MUST NOT spawn unbounded background tasks that stream into an `mpsc` channel without binding execution to a `tokio_util::sync::CancellationToken` or dropping the producer when the receiver drops.
- Services MUST ensure that database transactions and acquired connection guards (`sqlx::PoolConnection`, `deadpool`, etc.) are owned by the streaming future so RAII handles return connections to the pool immediately upon drop.
- Code SHOULD use `async_stream::try_stream!` or native `tokio_stream::Stream` adapters directly inside response bodies rather than manual task/channel synchronization primitives.
- Components NEVER swallow channel send errors or ignore cancellation signals inside long-running batch iterators or database cursor loops.

## Bad vs Good Implementations
### Database Cursor Streaming with TCP Disconnect Propagation

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Spawning an independent Tokio task to produce items into an mpsc channel disconnects the database iteration from Axum's downstream TCP body lifecycle. When the client aborts the connection, the response body drops the Receiver, but the database cursor task keeps running until it attempts to send into a full/closed channel buffer, holding a pooled connection and wasting CPU/RAM.
```rust
use axum::{body::Body, response::Response};
use tokio::sync::mpsc;
use tokio_stream::wrappers::ReceiverStream;
use futures::StreamExt;

pub async fn stream_handler(pool: sqlx::PgPool) -> Response {
    let (tx, rx) = mpsc::channel(100);

    // ANTI-PATTERN: Detached tokio::spawn runs independently of HTTP body drop.
    // If the client aborts TCP connection, this task keeps executing,
    // holding a database connection lease and running expensive queries.
    tokio::spawn(async move {
        let mut conn = pool.acquire().await.unwrap();
        let mut rows = sqlx::query!("SELECT * FROM large_audit_logs").fetch(&mut *conn);
        
        while let Some(Ok(row)) = rows.next().await {
            let json = serde_json::to_vec(&row.id).unwrap();
            // Only notices client drop if channel fills up and send fails;
            // if buffer is free, it keeps querying indefinitely.
            let _ = tx.send(Ok::<_, std::io::Error>(axum::body::Bytes::from(json))).await;
        }
    });

    Response::new(Body::from_stream(ReceiverStream::new(rx)))
}
```

#### Production Standard (Correct)
> **Standard**: Using `async_stream::try_stream!` keeps the entire execution lifecycle on the same call frame owned by the HTTP response `Body`. When the TCP socket closes prematurely, Axum drops the stream, executing the Rust drop guards for both the cursor and the `PoolConnection`, returning the connection to the pool instantly.
```rust
use axum::{body::Body, response::Response};
use async_stream::try_stream;
use futures::StreamExt;

pub async fn stream_handler(pool: sqlx::PgPool) -> Response {
    // INVARIANT: Own the connection lease directly within the stream future.
    // When the HTTP client disconnects, Axum drops the Body,
    // which drops the try_stream, immediately dropping the DB connection lease.
    let stream = try_stream! {
        let mut conn = pool.acquire().await.map_err(|e| std::io::Error::other(e))?;
        let mut rows = sqlx::query!("SELECT * FROM large_audit_logs").fetch(&mut *conn);

        while let Some(result) = rows.next().await {
            let row = result.map_err(|e| std::io::Error::other(e))?;
            let json = serde_json::to_vec(&row.id).map_err(|e| std::io::Error::other(e))?;
            yield axum::body::Bytes::from(json);
        }
    };

    Response::new(Body::from_stream(stream))
}
```

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 Structured Async Stream Cancellation and Resource Leakage Guardrail

Axum 0.8 Structured Async Stream Cancellation and Resource Leakage Guardrail defines an industrial-grade behavioral standard for backend engineering. Mandates deterministic cancellation propagation from Axum 0.8 HTTP streaming responses down to database cursors, channel consumers, and Tokio tasks. Prevents orphan background tasks, pinned database connection pools, and memory leaks when clients prematurely disconnect or abort TCP connections. 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: Detached Tokio Spawns and Unchecked Stream Consumers Causing Silent DB Connection Exhaustion on TCP Client Drop 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 DriftDetached Tokio Spawns and Unchecked Stream Consumers Causing Silent DB Connection Exhaustion on TCP Client DropCritical
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 tie streaming response lifecycles directly to the consumer stream rather than detaching worker loops via unmonitored `tokio

Engineers MUST ALWAYS tie streaming response lifecycles directly to the consumer stream rather than detaching worker loops via unmonitored `tokio::spawn`.

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 unbounded background tasks that stream into an `mpsc` channel without binding execution to a `tokio_util

Engineers MUST NOT spawn unbounded background tasks that stream into an `mpsc` channel without binding execution to a `tokio_util::sync::CancellationToken` or dropping the producer when the receiver drops.

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 ensure that database transactions and acquired connection guards (`sqlx

Services MUST ensure that database transactions and acquired connection guards (`sqlx::PoolConnection`, `deadpool`, etc.) are owned by the streaming future so RAII handles return connections to the pool immediately upon drop.

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 use `async_stream

Code SHOULD use `async_stream::try_stream!` or native `tokio_stream::Stream` adapters directly inside response bodies rather than manual task/channel synchronization primitives.

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

Components NEVER swallow channel send errors or ignore cancellation signals inside long-running batch iterators or database cursor loops.

Components NEVER swallow channel send errors or ignore cancellation signals inside long-running batch iterators or database cursor loops.

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 Structured Async Stream Cancellation and Resource Leakage Guardrail critical for AI coding assistants?

Mandates deterministic cancellation propagation from Axum 0.8 HTTP streaming responses down to database cursors, channel consumers, and Tokio tasks. Prevents orphan background tasks, pinned database connection pools, and memory leaks when clients prematurely disconnect or abort TCP connections. 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 (Detached Tokio Spawns and Unchecked Stream Consumers Causing Silent DB Connection Exhaustion on TCP Client Drop) 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