This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: fastapi-anyio-connection-drop-shielding

FastAPI AnyIO TaskGroup Connection-Drop Shielding & Cleanup Invariant

Enforces AnyIO structured concurrency task groups and shielded cleanup scopes across all streaming and long-lived FastAPI endpoints. Guarantees complete transactional rollbacks, external resource deallocation, and state auditing when clients abruptly terminate HTTP connections, completely preventing unhandled coroutine leaks and orphaned background tasks.

Prohibited Anti-Pattern: Unshielded Cleanup Routines and Unstructured asyncio.create_task Leaks on Abrupt Client Disconnects

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: FastAPI AnyIO TaskGroup Connection-Drop Shielding & Cleanup Invariant - Enforces AnyIO structured concurrency task groups and shielded cleanup scopes across all streaming and long-lived FastAPI endpoints. Guarantees complete transactional rollbacks, external resource deallocation, and state auditing when clients abruptly terminate HTTP connections, completely preventing unhandled coroutine leaks and orphaned background tasks.
globs: app/**/*.py, src/**/*.py, api/**/*.py
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/fastapi-anyio-connection-drop-shielding"
---

# FastAPI AnyIO TaskGroup Connection-Drop Shielding & Cleanup Invariant

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Unshielded Cleanup Routines and Unstructured asyncio.create_task Leaks on Abrupt Client Disconnects

## System Constraints
You are a Principal Backend Architect enforcing strict structured concurrency and transactional safety in FastAPI and AnyIO applications. Client disconnects (ASGI cancellation) must propagate cleanly through structured task groups, while cleanup, rollback, and auditing tasks must execute within shielded AnyIO cancellation scopes without leaving zombie coroutines or hung worker threads.

## Strict Guidelines
- Engineers MUST ALWAYS use `anyio.create_task_group()` instead of bare `asyncio.create_task()` or `asyncio.gather()` for spawning concurrent subtasks within endpoint lifecycles.
- Engineers MUST wrap all critical resource cleanups, database rollbacks, and audit logging in `with anyio.CancelScope(shield=True):` inside `finally` blocks when handling streaming endpoints or cancelable async workflows.
- Engineers MUST NOT swallow `anyio.get_cancelled_exc_class()` or `asyncio.CancelledError`; cancellations must be allowed to propagate to ASGI servers (e.g., Uvicorn) to recycle socket descriptors.
- Code SHOULD regularly check `await request.is_disconnected()` in high-latency or long-running streaming generators to trigger early exit before starting expensive processing steps.
- Services MUST NEVER fire detached background tasks without an explicit, centrally managed background worker queue (e.g., Celery, ARQ, SAQ) or an application-lifespan-scoped AnyIO task group.
- Components NEVER execute raw async database write transactions inside an unshielded cancellation context during connection tear-down.

## Bad vs Good Implementations
### Streaming Generator Connection Teardown and Resource Shielding

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Using asyncio.create_task causes orphaned coroutines that outlive the client request lifecycle. Performing async cleanup in an unshielded 'finally' block causes the ASGI cancellation exception to interrupt the rollback and GPU release mid-flight, leaking hardware resources and corrupting connection pools.
```python
import asyncio
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse

app = FastAPI()

@app.post("/stream/generate")
async def stream_generation(request: Request):
    # ANTI-PATTERN: Spawns fire-and-forget task without structured scope
    # If the client disconnects, task continues running indefinitely (orphaned coroutine leak)
    asyncio.create_task(audit_log_start(request))

    async def event_generator():
        try:
            for i in range(100):
                await asyncio.sleep(0.5)
                yield f"data: chunk_{i}\n\n"
        finally:
            # ANTI-PATTERN: When client disconnects, CancelledError is raised immediately
            # during this await, terminating the DB rollback mid-execution
            await db_session.rollback()
            await release_gpu_slot()

    return StreamingResponse(event_generator(), media_type="text/event-stream")
```

#### Production Standard (Correct)
> **Standard**: Using anyio.create_task_group guarantees all auxiliary coroutines are bound to the generator lifecycle. Wrapping cleanup routines within anyio.CancelScope(shield=True) ensures database rollbacks and GPU releases complete fully even when client socket cancellation aborts the primary response stream.
```python
import anyio
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse

app = FastAPI()

@app.post("/stream/generate")
async def stream_generation(request: Request):
    async def event_generator():
        # Invariant: Structured concurrency using AnyIO TaskGroup
        async with anyio.create_task_group() as tg:
            # Register subtasks within the structured group
            tg.start_soon(audit_log_start, request.client.host)
            try:
                for i in range(100):
                    # Proactive disconnect detection
                    if await request.is_disconnected():
                        raise anyio.get_cancelled_exc_class()()
                    
                    await anyio.sleep(0.5)
                    yield f"data: chunk_{i}\n\n"
            finally:
                # Invariant: Shield critical resource cleanup from ASGI cancellation
                with anyio.CancelScope(shield=True):
                    await db_session.rollback()
                    await release_gpu_slot()
                # Structured TaskGroup automatically awaits tg child tasks before exiting

    return StreamingResponse(event_generator(), media_type="text/event-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: FastAPI AnyIO TaskGroup Connection-Drop Shielding & Cleanup Invariant

FastAPI AnyIO TaskGroup Connection-Drop Shielding & Cleanup Invariant defines an industrial-grade behavioral standard for backend engineering. Enforces AnyIO structured concurrency task groups and shielded cleanup scopes across all streaming and long-lived FastAPI endpoints. Guarantees complete transactional rollbacks, external resource deallocation, and state auditing when clients abruptly terminate HTTP connections, completely preventing unhandled coroutine leaks and orphaned background tasks. 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: Unshielded Cleanup Routines and Unstructured asyncio.create_task Leaks on Abrupt Client Disconnects 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 DriftUnshielded Cleanup Routines and Unstructured asyncio.create_task Leaks on Abrupt Client DisconnectsCritical
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 use `anyio.create_task_group()` instead of bare `asyncio.create_task()` or `asyncio.gather()` for spawning concurrent subtasks within endpoint lifecycles.

Engineers MUST ALWAYS use `anyio.create_task_group()` instead of bare `asyncio.create_task()` or `asyncio.gather()` for spawning concurrent subtasks within endpoint 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.
2

Engineers MUST wrap all critical resource cleanups, database rollbacks, and audit logging in `with anyio.CancelScope(shield=True)

Engineers MUST wrap all critical resource cleanups, database rollbacks, and audit logging in `with anyio.CancelScope(shield=True):` inside `finally` blocks when handling streaming endpoints or cancelable async workflows.

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 swallow `anyio.get_cancelled_exc_class()` or `asyncio.CancelledError`

Engineers MUST NOT swallow `anyio.get_cancelled_exc_class()` or `asyncio.CancelledError`; cancellations must be allowed to propagate to ASGI servers (e.g., Uvicorn) to recycle socket descriptors.

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 regularly check `await request.is_disconnected()` in high-latency or long-running streaming generators to trigger early exit before starting expensive processing steps.

Code SHOULD regularly check `await request.is_disconnected()` in high-latency or long-running streaming generators to trigger early exit before starting expensive processing steps.

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 NEVER fire detached background tasks without an explicit, centrally managed background worker queue (e.g., Celery, ARQ, SAQ) or an application-lifespan-scoped AnyIO task group.

Services MUST NEVER fire detached background tasks without an explicit, centrally managed background worker queue (e.g., Celery, ARQ, SAQ) or an application-lifespan-scoped AnyIO task group.

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 execute raw async database write transactions inside an unshielded cancellation context during connection tear-down.

Components NEVER execute raw async database write transactions inside an unshielded cancellation context during connection 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.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is FastAPI AnyIO TaskGroup Connection-Drop Shielding & Cleanup Invariant critical for AI coding assistants?

Enforces AnyIO structured concurrency task groups and shielded cleanup scopes across all streaming and long-lived FastAPI endpoints. Guarantees complete transactional rollbacks, external resource deallocation, and state auditing when clients abruptly terminate HTTP connections, completely preventing unhandled coroutine leaks and orphaned background tasks. 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 (Unshielded Cleanup Routines and Unstructured asyncio.create_task Leaks on Abrupt Client Disconnects) 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

FastAPI