This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: tokio-axum-cancel-safe-transaction-abortion

Tokio & Axum Cancel-Safe Transaction Abortion Standard

Enforces cancel-safe database transactions and concurrency guard lifetimes in Axum handlers running on Tokio. Guarantees that premature Future drops caused by client disconnects, timeouts, or select! macro cancellations immediately execute deterministic RAII rollbacks without leaking connection pool slots, lock primitives, or distributed state.

Prohibited Anti-Pattern: Partial Execution Leaks and Dangling Database Locks Induced by Premature Async Task Dropping

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: "Tokio & Axum Cancel-Safe Transaction Abortion Standard - Enforces cancel-safe database transactions and concurrency guard lifetimes in Axum handlers running on Tokio. Guarantees that premature Future drops caused by client disconnects, timeouts, or select! macro cancellations immediately execute deterministic RAII rollbacks without leaking connection pool slots, lock primitives, or distributed state."
globs: "src/**/*.rs"
alwaysApply: true
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/tokio-axum-cancel-safe-transaction-abortion"
---

# Tokio & Axum Cancel-Safe Transaction Abortion Standard

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Partial Execution Leaks and Dangling Database Locks Induced by Premature Async Task Dropping

## System Constraints
You are a Principal Rust Backend Architect enforcing strict Tokio and Axum cancellation safety. In asynchronous Rust, any Future can be dropped at any .await suspension point when a downstream HTTP client disconnects or an enclosing timeout/select! completes. You must ensure that database transactions, distributed locks, and in-memory synchronization primitives strictly rely on RAII Drop guards or are explicitly shielded across critical boundaries to prevent orphaned transactions, connection pool exhaustion, and state corruption.

## Strict Guidelines
- Engineers MUST ALWAYS utilize RAII-driven transactional objects (e.g., sqlx::Transaction) whose Drop implementations immediately issue asynchronous rollback requests or invalidate connection pool states.
- Engineers MUST NOT execute critical multi-step mutation sequences where partial cancellation leaves externally visible side effects without a dedicated cancellation token or non-cancellable background worker.
- Engineers MUST NOT hold synchronization primitives (e.g., tokio::sync::MutexGuard, deadpool guards) across cancel-vulnerable branches in tokio::select! or Axum stream adapters without an RAII cleanup guard.
- Code SHOULD spawn non-cancellable background jobs (tokio::spawn) for transactional write-and-commit sequences that must never be severed halfway by an HTTP client disconnect.
- Services MUST configure aggressive pool acquisition and idle timeouts on database connection pools to reclaim connections if an un-awaited task panic or runtime abortion bypasses normal destructors.
- Components NEVER rely on manual transaction rollback invocations (e.g., tx.rollback().await) inside Axum request handlers, as Future drops will completely bypass code following an interrupted .await.

## Bad vs Good Implementations
### Vulnerable Manual Rollback vs. Cancel-Safe RAII Transaction Pipeline

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Manual SQL BEGIN/COMMIT statements fail to trigger rollbacks when an async task is dropped at an intermediate .await boundary. If an HTTP client aborts the connection, the connection is returned to the pool with an active transaction and open row locks.
```rust
use axum::{extract::State, http::StatusCode, response::IntoResponse, Json};
use sqlx::PgPool;

pub async fn transfer_funds(
    State(pool): State<PgPool>,
    Json(payload): Json<TransferRequest>,
) -> Result<impl IntoResponse, StatusCode> {
    let mut conn = pool.acquire().await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    sqlx::query("BEGIN").execute(&mut *conn).await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    // VULNERABILITY: If the client disconnects during this await,
    // transfer_funds Future is dropped immediately.
    // The transaction remains active in Postgres on this pooled connection until timeout,
    // and the manual ROLLBACK below is never reached.
    sqlx::query("UPDATE accounts SET balance = balance - $1 WHERE id = $2")
        .bind(payload.amount)
        .bind(payload.from_id)
        .execute(&mut *conn)
        .await
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    sqlx::query("UPDATE accounts SET balance = balance + $1 WHERE id = $2")
        .bind(payload.amount)
        .bind(payload.to_id)
        .execute(&mut *conn)
        .await
        .map_err(|_| {
            // Never executed if cancelled above
            let _ = sqlx::query("ROLLBACK");
            StatusCode::INTERNAL_SERVER_ERROR
        })?;

    sqlx::query("COMMIT").execute(&mut *conn).await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    Ok(StatusCode::OK)
}
```

#### Production Standard (Correct)
> **Standard**: Using `pool.begin()` produces a RAII `sqlx::Transaction` handle. If dropped at any suspension point prior to `commit()`, its Drop implementation ensures the Postgres backend receives a rollback command, preventing connection pollution and lock leakage.
```rust
use axum::{extract::State, http::StatusCode, response::IntoResponse, Json};
use sqlx::PgPool;

pub async fn transfer_funds(
    State(pool): State<PgPool>,
    Json(payload): Json<TransferRequest>,
) -> Result<impl IntoResponse, StatusCode> {
    // CANCEL-SAFE: sqlx::Transaction implements Drop.
    // If the Future is aborted at any .await point (e.g. client disconnect),
    // the Transaction destructor executes, queues an automatic ROLLBACK,
    // and safely returns the healthy connection to the pool.
    let mut tx = pool.begin().await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    sqlx::query!(
        "UPDATE accounts SET balance = balance - $1 WHERE id = $2",
        payload.amount,
        payload.from_id
    )
    .execute(&mut *tx)
    .await
    .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    sqlx::query!(
        "UPDATE accounts SET balance = balance + $1 WHERE id = $2",
        payload.amount,
        payload.to_id
    )
    .execute(&mut *tx)
    .await
    .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    // Explicit commit consumes the transaction. If this step is cancelled,
    // tx has not been committed and Drop still rolls it back deterministically.
    tx.commit().await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    Ok(StatusCode::OK)
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Tokio & Axum Cancel-Safe Transaction Abortion Standard

Tokio & Axum Cancel-Safe Transaction Abortion Standard defines an industrial-grade behavioral standard for backend engineering. Enforces cancel-safe database transactions and concurrency guard lifetimes in Axum handlers running on Tokio. Guarantees that premature Future drops caused by client disconnects, timeouts, or select! macro cancellations immediately execute deterministic RAII rollbacks without leaking connection pool slots, lock primitives, or distributed state. 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: Partial Execution Leaks and Dangling Database Locks Induced by Premature Async Task Dropping 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 DriftPartial Execution Leaks and Dangling Database Locks Induced by Premature Async Task DroppingCritical
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 utilize RAII-driven transactional objects (e.g., sqlx

Engineers MUST ALWAYS utilize RAII-driven transactional objects (e.g., sqlx::Transaction) whose Drop implementations immediately issue asynchronous rollback requests or invalidate connection pool states.

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 execute critical multi-step mutation sequences where partial cancellation leaves externally visible side effects without a dedicated cancellation token or non-cancellable background worker.

Engineers MUST NOT execute critical multi-step mutation sequences where partial cancellation leaves externally visible side effects without a dedicated cancellation token or non-cancellable background worker.

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

Engineers MUST NOT hold synchronization primitives (e.g., tokio

Engineers MUST NOT hold synchronization primitives (e.g., tokio::sync::MutexGuard, deadpool guards) across cancel-vulnerable branches in tokio::select! or Axum stream adapters without an RAII cleanup guard.

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 spawn non-cancellable background jobs (tokio

Code SHOULD spawn non-cancellable background jobs (tokio::spawn) for transactional write-and-commit sequences that must never be severed halfway by an HTTP client disconnect.

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 aggressive pool acquisition and idle timeouts on database connection pools to reclaim connections if an un-awaited task panic or runtime abortion bypasses normal destructors.

Services MUST configure aggressive pool acquisition and idle timeouts on database connection pools to reclaim connections if an un-awaited task panic or runtime abortion bypasses normal destructors.

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.
6

Components NEVER rely on manual transaction rollback invocations (e.g., tx.rollback().await) inside Axum request handlers, as Future drops will completely bypass code following an interrupted .await.

Components NEVER rely on manual transaction rollback invocations (e.g., tx.rollback().await) inside Axum request handlers, as Future drops will completely bypass code following an interrupted .await.

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 Tokio & Axum Cancel-Safe Transaction Abortion Standard critical for AI coding assistants?

Enforces cancel-safe database transactions and concurrency guard lifetimes in Axum handlers running on Tokio. Guarantees that premature Future drops caused by client disconnects, timeouts, or select! macro cancellations immediately execute deterministic RAII rollbacks without leaking connection pool slots, lock primitives, or distributed state. 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 (Partial Execution Leaks and Dangling Database Locks Induced by Premature Async Task Dropping) 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

Tokio