This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: axum-tower-cancellation-socket-drain-guardrail

Axum 0.8 Deterministic Async Cancellation & Graceful Stream Socket Drain

Enforces strict cancellation safety and deterministic resource cleanup within Axum 0.8 and Hyper streaming handlers. Eliminates database transaction pool starvation, stale locks, and partial state mutations caused by silent future drops during abrupt HTTP/3 QUIC connection resets.

Prohibited Anti-Pattern: Bare Transaction Handles and Unshielded Asynchronous Finalization in Droppable Stream Contexts

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Axum 0.8 Deterministic Async Cancellation & Graceful Stream Socket Drain - Enforces strict cancellation safety and deterministic resource cleanup within Axum 0.8 and Hyper streaming handlers. Eliminates database transaction pool starvation, stale locks, and partial state mutations caused by silent future drops during abrupt HTTP/3 QUIC connection resets.
globs: src/**/*.rs
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/axum-tower-cancellation-socket-drain-guardrail"
---

# Axum 0.8 Deterministic Async Cancellation & Graceful Stream Socket Drain

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Bare Transaction Handles and Unshielded Asynchronous Finalization in Droppable Stream Contexts

## System Constraints
You are a Principal Systems Engineer enforcing strict async cancellation safety, RAII-based resource deallocation, and Hyper socket drain mechanics in Axum 0.8. In Rust asynchronous runtimes, any client disconnect immediately drops the active response future at its current await point. You must mandate patterns that prevent lingering locks, partial database state, and socket resource exhaustion.

## Strict Guidelines
- Engineers MUST ALWAYS isolate state-mutating operations from droppable streaming loops using dedicated transactional tasks or tokio::spawn boundaries.
- Engineers MUST NOT hold active, uncommitted database transactions across untrusted client-controlled I/O yield points (e.g., SSE, WebSocket frames, or raw HTTP/3 chunk bodies).
- Services MUST implement explicit RAII Drop guards (or employ tokio_util::sync::CancellationToken) to detect client aborts and execute compensatory rollbacks deterministically.
- Code SHOULD leverage Axum 0.8's Body::from_stream combined with tokio_stream::StreamExt and hyper socket drain hooks to flush trailing frames before completing tear-down.
- Components NEVER rely on sequential code following a streaming await point for cleanup, as async futures dropped by Hyper will skip all downstream instructions.

## Bad vs Good Implementations
### Preventing Dangling DB Locks and Broken State on Premature Stream Disconnect

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: When an HTTP/3 client drops the connection or sends a RESET_STREAM frame, Hyper terminates the handler future immediately. The code inside try_stream! stops executing, skipping the status update to 'COMPLETED' and the explicit tx.commit(). The database transaction remains open until dropped, causing pool exhaustion and uncommitted locks.
```rust
use axum::{body::Body, extract::State, response::Response, http::StatusCode};
use sqlx::PgPool;
use tokio::time::{sleep, Duration};

pub async fn stream_export(
    State(pool): State<PgPool>,
) -> Result<Response, StatusCode> {
    let mut tx = pool.begin().await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    // Mutate state prior to streaming
    sqlx::query!("UPDATE exports SET status = 'STREAMING' WHERE id = 1")
        .execute(&mut *tx)
        .await
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    // ANTI-PATTERN: tx is held across streaming yield points.
    // If the HTTP/3 stream terminates early, this future is dropped instantly.
    // Downstream cleanup and commit are skipped; transaction leaks until pool timeout.
    let stream = async_stream::try_stream! {
        for i in 0..100 {
            sleep(Duration::from_millis(50)).await;
            yield format!("chunk {i}\n");
        }
        sqlx::query!("UPDATE exports SET status = 'COMPLETED' WHERE id = 1")
            .execute(&mut *tx)
            .await
            .unwrap();
        tx.commit().await.unwrap();
    };

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

#### Production Standard (Correct)
> **Standard**: Decouples stream production from the client socket lifecycle via a bounded channel and CancellationToken. If the client disconnects, the StreamGuard fires on drop, signalling the detached background task to gracefully finalize the database transaction with an 'ABORTED' status and clean up resources without leaving dangling locks.
```rust
use axum::{body::Body, extract::State, response::Response, http::StatusCode};
use sqlx::PgPool;
use tokio_util::sync::CancellationToken;
use tokio::sync::mpsc;
use tokio_stream::wrappers::ReceiverStream;

pub async fn stream_export(
    State(pool): State<PgPool>,
) -> Result<Response, StatusCode> {
    let token = CancellationToken::new();
    let (tx_chan, rx_chan) = mpsc::channel::<Result<String, std::io::Error>>(16);
    
    // SPAWN CRITICAL PATH: Shield background processing from direct connection drop
    let cancel_token = token.clone();
    tokio::spawn(async move {
        let mut tx = match pool.begin().await {
            Ok(t) => t,
            Err(_) => return,
        };

        let _ = sqlx::query!("UPDATE exports SET status = 'STREAMING' WHERE id = 1")
            .execute(&mut *tx)
            .await;

        let mut completed = true;
        for i in 0..100 {
            tokio::select! {
                biased;
                _ = cancel_token.cancelled() => {
                    completed = false;
                    break;
                }
                send_res = tx_chan.send(Ok(format!("chunk {i}\n"))) => {
                    if send_res.is_err() { completed = false; break; }
                }
            }
        }

        let final_status = if completed { "COMPLETED" } else { "ABORTED" };
        let _ = sqlx::query!("UPDATE exports SET status = $1 WHERE id = 1", final_status)
            .execute(&mut *tx)
            .await;
        let _ = tx.commit().await;
    });

    // Custom drop guard notifies token when client disconnects or body is discarded
    struct StreamGuard(CancellationToken);
    impl Drop for StreamGuard {
        fn drop(&mut self) { self.0.cancel(); }
    }
    let _guard = StreamGuard(token);

    let body_stream = ReceiverStream::new(rx_chan);
    Ok(Response::new(Body::from_stream(body_stream)))
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Axum 0.8 Deterministic Async Cancellation & Graceful Stream Socket Drain

Axum 0.8 Deterministic Async Cancellation & Graceful Stream Socket Drain defines an industrial-grade behavioral standard for backend engineering. Enforces strict cancellation safety and deterministic resource cleanup within Axum 0.8 and Hyper streaming handlers. Eliminates database transaction pool starvation, stale locks, and partial state mutations caused by silent future drops during abrupt HTTP/3 QUIC connection resets. 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: Bare Transaction Handles and Unshielded Asynchronous Finalization in Droppable Stream Contexts 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 DriftBare Transaction Handles and Unshielded Asynchronous Finalization in Droppable Stream ContextsCritical
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 isolate state-mutating operations from droppable streaming loops using dedicated transactional tasks or tokio

Engineers MUST ALWAYS isolate state-mutating operations from droppable streaming loops using dedicated transactional tasks or tokio::spawn boundaries.

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 hold active, uncommitted database transactions across untrusted client-controlled I/O yield points (e.g., SSE, WebSocket frames, or raw HTTP/3 chunk bodies).

Engineers MUST NOT hold active, uncommitted database transactions across untrusted client-controlled I/O yield points (e.g., SSE, WebSocket frames, or raw HTTP/3 chunk bodies).

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 implement explicit RAII Drop guards (or employ tokio_util

Services MUST implement explicit RAII Drop guards (or employ tokio_util::sync::CancellationToken) to detect client aborts and execute compensatory rollbacks deterministically.

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 leverage Axum 0.8's Body

Code SHOULD leverage Axum 0.8's Body::from_stream combined with tokio_stream::StreamExt and hyper socket drain hooks to flush trailing frames before completing tear-down.

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 rely on sequential code following a streaming await point for cleanup, as async futures dropped by Hyper will skip all downstream instructions.

Components NEVER rely on sequential code following a streaming await point for cleanup, as async futures dropped by Hyper will skip all downstream instructions.

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 Deterministic Async Cancellation & Graceful Stream Socket Drain critical for AI coding assistants?

Enforces strict cancellation safety and deterministic resource cleanup within Axum 0.8 and Hyper streaming handlers. Eliminates database transaction pool starvation, stale locks, and partial state mutations caused by silent future drops during abrupt HTTP/3 QUIC connection resets. 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 (Bare Transaction Handles and Unshielded Asynchronous Finalization in Droppable Stream Contexts) 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