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

Axum 0.8 Cancellation Safety and RAII Rollback in Async Database Transactions

Enforces strict cancellation safety invariants across Axum 0.8 handlers holding database connections and transactions. Guarantees that premature HTTP client disconnections during async stream evaluation or unbounded yield points immediately trigger deterministic RAII rollbacks rather than starving connection pools, abandoning uncommitted transactions, or executing partial transactional side-effects.

Prohibited Anti-Pattern: Holding Open Database Transactions Across Unbounded Client Streaming Yields Causing Pool Exhaustion on Cancellation

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Axum 0.8 Cancellation Safety and RAII Rollback in Async Database Transactions - Enforces strict cancellation safety invariants across Axum 0.8 handlers holding database connections and transactions. Guarantees that premature HTTP client disconnections during async stream evaluation or unbounded yield points immediately trigger deterministic RAII rollbacks rather than starving connection pools, abandoning uncommitted transactions, or executing partial transactional side-effects.
globs: src/**/*.rs
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/axum-0-8-transaction-cancellation-safety"
---

# Axum 0.8 Cancellation Safety and RAII Rollback in Async Database Transactions

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Holding Open Database Transactions Across Unbounded Client Streaming Yields Causing Pool Exhaustion on Cancellation

## System Constraints
You are a Principal Rust Backend Architect enforcing Axum 0.8 and SQLx/deadpool transaction lifecycle safety. In Tokio/Axum runtimes, client disconnections drop request handler futures synchronously at the nearest await point. You must ensure that database write transactions are NEVER held across unbounded response streams or non-cancellation-safe async blocks. Any operation that modifies transactional state must either run to completion inside a detached, shielded task or rely on explicit RAII Drop rollbacks without leaving active pool connections in indeterminate states.

## Strict Guidelines
- Engineers MUST NEVER hold an active write transaction (`sqlx::Transaction`) across an unbounded HTTP streaming yield point (e.g., SSE, chunked transfer, or `Body::from_stream`).
- Engineers MUST isolate transactional mutations from client disconnect drops by wrapping atomic write operations in self-contained async functions or using shielded background tasks (`tokio::spawn`) when operations must be decoupled from client transport lifecycles.
- Code MUST rely on RAII transaction ownership semantics where dropping a `Transaction` automatically sends an asynchronous ROLLBACK to the connection pool, rather than relying on manual, post-yield `tx.commit().await` calls.
- Streaming endpoints MUST stream exclusively over read-only cursor snapshots or disconnected read replicas, releasing the pool connection as early as possible before initiating HTTP response encoding.
- Services MUST configure connection pool acquisition timeouts (`acquire_timeout`) and idle transaction timeouts at the database driver level to defend against deadlocks caused by abandoned futures.

## Bad vs Good Implementations
### Unsafe Transaction Held Across Async Response Stream vs. Atomic Ingestion with Read-Only Stream

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: When an HTTP client aborts the connection mid-stream, Axum drops the stream future immediately. The `tx.commit().await` line is unreachable, leaving table/row locks active for the duration of the stream. While SQLx transactions roll back on Drop, holding open transactions during slow client streaming starves the connection pool.
```rust
use axum::{body::Body, response::Response, extract::State};
use sqlx::PgPool;
use futures_util::stream;

pub async fn export_and_update(State(pool): State<PgPool>) -> Response {
    // ANTI-PATTERN: Transaction opened across an unbounded streaming body.
    let mut tx = pool.begin().await.unwrap();

    let stream = async_stream::stream! {
        for i in 0..10_000 {
            // Database mutation occurring lazily within client stream
            sqlx::query("UPDATE reports SET processed_chunks = $1 WHERE id = 42")
                .bind(i)
                .execute(&mut *tx)
                .await
                .unwrap();

            yield Ok::<_, std::io::Error>(format!("chunk {}\n", i));
        }
        // If client disconnects early, the future is dropped above.
        // tx.commit() is never reached; locks are held until pool timeout.
        tx.commit().await.unwrap();
    };

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

#### Production Standard (Correct)
> **Standard**: All transactional state mutations complete and commit prior to initiating the streaming response. The streaming phase uses read-only pool queries (`fetch`). If the client aborts, the read stream is dropped cleanly without holding write locks or leaving pending uncommitted transactions.
```rust
use axum::{body::Body, extract::State, response::{IntoResponse, Response}, http::StatusCode};
use sqlx::PgPool;
use tokio_stream::StreamExt;

pub async fn export_and_update(State(pool): State<PgPool>) -> Result<Response, (StatusCode, String)> {
    // 1. Execute transactional writes atomically BEFORE streaming to client.
    // Future is cancellation-safe: RAII rollback executes if dropped before commit.
    {
        let mut tx = pool.begin().await.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
        sqlx::query("UPDATE reports SET status = 'exporting' WHERE id = 42")
            .execute(&mut *tx)
            .await
            .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
        tx.commit().await.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
    }

    // 2. Stream read-only data via independent cursor that can be safely dropped.
    let stream = sqlx::query_as::<_, (i32, String)>("SELECT chunk_id, payload FROM report_data WHERE report_id = 42")
        .fetch(&pool)
        .map(|row| match row {
            Ok((id, payload)) => Ok::<_, std::io::Error>(format!("{}: {}\n", id, payload)),
            Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())),
        });

    Ok(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 Cancellation Safety and RAII Rollback in Async Database Transactions

Axum 0.8 Cancellation Safety and RAII Rollback in Async Database Transactions defines an industrial-grade behavioral standard for backend engineering. Enforces strict cancellation safety invariants across Axum 0.8 handlers holding database connections and transactions. Guarantees that premature HTTP client disconnections during async stream evaluation or unbounded yield points immediately trigger deterministic RAII rollbacks rather than starving connection pools, abandoning uncommitted transactions, or executing partial transactional side-effects. 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: Holding Open Database Transactions Across Unbounded Client Streaming Yields Causing Pool Exhaustion on Cancellation 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 DriftHolding Open Database Transactions Across Unbounded Client Streaming Yields Causing Pool Exhaustion on CancellationCritical
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 NEVER hold an active write transaction (`sqlx

Engineers MUST NEVER hold an active write transaction (`sqlx::Transaction`) across an unbounded HTTP streaming yield point (e.g., SSE, chunked transfer, or `Body::from_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.
2

Engineers MUST isolate transactional mutations from client disconnect drops by wrapping atomic write operations in self-contained async functions or using shielded background tasks (`tokio

Engineers MUST isolate transactional mutations from client disconnect drops by wrapping atomic write operations in self-contained async functions or using shielded background tasks (`tokio::spawn`) when operations must be decoupled from client transport lifecycles.

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 rely on RAII transaction ownership semantics where dropping a `Transaction` automatically sends an asynchronous ROLLBACK to the connection pool, rather than relying on manual, post-yield `tx.commit().await` calls.

Code MUST rely on RAII transaction ownership semantics where dropping a `Transaction` automatically sends an asynchronous ROLLBACK to the connection pool, rather than relying on manual, post-yield `tx.commit().await` calls.

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

Streaming endpoints MUST stream exclusively over read-only cursor snapshots or disconnected read replicas, releasing the pool connection as early as possible before initiating HTTP response encoding.

Streaming endpoints MUST stream exclusively over read-only cursor snapshots or disconnected read replicas, releasing the pool connection as early as possible before initiating HTTP response encoding.

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 configure connection pool acquisition timeouts (`acquire_timeout`) and idle transaction timeouts at the database driver level to defend against deadlocks caused by abandoned futures.

Services MUST configure connection pool acquisition timeouts (`acquire_timeout`) and idle transaction timeouts at the database driver level to defend against deadlocks caused by abandoned futures.

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 Cancellation Safety and RAII Rollback in Async Database Transactions critical for AI coding assistants?

Enforces strict cancellation safety invariants across Axum 0.8 handlers holding database connections and transactions. Guarantees that premature HTTP client disconnections during async stream evaluation or unbounded yield points immediately trigger deterministic RAII rollbacks rather than starving connection pools, abandoning uncommitted transactions, or executing partial transactional side-effects. 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 (Holding Open Database Transactions Across Unbounded Client Streaming Yields Causing Pool Exhaustion on Cancellation) 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