This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: go-chi-v5-context-afterfunc-cleanup-orchestration

Deterministic Resource Cleanup and Rollbacks with Chi v5 and context.AfterFunc

Enforces asynchronous, non-blocking distributed resource cancellation and database transaction rollbacks upon client connection termination (such as HTTP/3 QUIC stream resets) using Go 1.21+ `context.AfterFunc`. Prevents orphan lock retention, dangling distributed leases, and zombie worker routines when a client disconnects prior to HTTP handler completion in Chi v5 routers.

Prohibited Anti-Pattern: Relying Exclusively on Synchronous Defer Blocks and Epoll Context Checks in Handlers

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Deterministic Resource Cleanup and Rollbacks with Chi v5 and context.AfterFunc - Enforces asynchronous, non-blocking distributed resource cancellation and database transaction rollbacks upon client connection termination (such as HTTP/3 QUIC stream resets) using Go 1.21+ `context.AfterFunc`. Prevents orphan lock retention, dangling distributed leases, and zombie worker routines when a client disconnects prior to HTTP handler completion in Chi v5 routers.
globs: **/*.go
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/go-chi-v5-context-afterfunc-cleanup-orchestration"
---

# Deterministic Resource Cleanup and Rollbacks with Chi v5 and context.AfterFunc

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Relying Exclusively on Synchronous Defer Blocks and Epoll Context Checks in Handlers

## System Constraints
You are a Principal Backend Architect enforcing strict cancellation lifecycle guarantees in Go Chi v5 services. Mandate deterministic cleanup via context.AfterFunc for any long-lived or distributed resources initialized during request lifecycles.

## Strict Guidelines
- Engineers MUST ALWAYS register an asynchronous teardown callback via `context.AfterFunc(r.Context(), ...)` for distributed locks, lease renewals, or external queue reservations immediately after acquisition.
- Engineers MUST ensure that any `stop()` function returned by `context.AfterFunc` is invoked in a standard `defer` block to dereference callbacks and prevent memory leaks upon normal handler completion.
- Engineers MUST NOT run blocking I/O directly inside the `context.AfterFunc` callback without spawning a detached goroutine protected by a bounded background context (`context.WithoutCancel`).
- Services MUST orchestrate transactional aborts defensively, verifying whether a transaction is already committed before attempting an `AfterFunc`-triggered rollback.
- Components NEVER rely solely on polling `ctx.Done()` in deeply nested internal packages when external distributed leases must be yielded to other cluster nodes instantly upon HTTP/3 stream drops.

## Bad vs Good Implementations
### Handling Client Disconnects with context.AfterFunc in Chi v5

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Traditional `defer tx.Rollback()` executes synchronously only when the enclosing handler function returns. In scenarios with long-running downstream RPCs or I/O unblocking delays after an HTTP/3 client drops, database locks and server resources remain held unnecessarily.
```go
package handlers

import (
	"database/sql"
	"net/http"
	"github.com/go-chi/chi/v5"
)

func MountOrderRoutes(r chi.Router, db *sql.DB) {
	r.Post("/orders", func(w http.ResponseWriter, r *http.Request) {
		tx, err := db.BeginTx(r.Context(), nil)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		// Anti-pattern: If client drops (HTTP/3 STREAM_RESET) while handler
		// is waiting on a slow external call or uncooperative driver,
		// tx.Rollback() does not run until the handler function finally returns,
		// retaining table row locks and distributed state indefinitely.
		defer tx.Rollback()

		if err := processLongOrder(r.Context(), tx); err != nil {
			http.Error(w, err.Error(), http.StatusBadGateway)
			return
		}

		if err := tx.Commit(); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.WriteHeader(http.StatusCreated)
	})
}
```

#### Production Standard (Correct)
> **Standard**: `context.AfterFunc` registers an event-driven callback that fires immediately upon client transport disconnection or stream reset. Using `atomic.Bool` guards against duplicate commits/rollbacks, `context.WithoutCancel` allows graceful out-of-band resource cleanup, and executing `stopCleanup()` prevents memory retention of the callback.
```go
package handlers

import (
	"context"
	"database/sql"
	"errors"
	"net/http"
	"sync/atomic"
	"time"

	"github.com/go-chi/chi/v5"
)

func MountOrderRoutes(r chi.Router, db *sql.DB) {
	r.Post("/orders", func(w http.ResponseWriter, r *http.Request) {
		ctx := r.Context()
		tx, err := db.BeginTx(ctx, nil)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		var committed atomic.Bool

		// Register immediate asynchronous cleanup callback on context cancellation
		stopCleanup := context.AfterFunc(ctx, func() {
			if !committed.Load() {
				// Use detached bounded context for emergency teardown to bypass cancelled ctx
				cleanupCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second)
				defer cancel()
				_ = tx.Rollback()
				_ = cleanupDistributedLease(cleanupCtx)
			}
		})
		// Deregister callback immediately when handler terminates normally to prevent leaks
		defer stopCleanup()

		if err := processLongOrder(ctx, tx); err != nil {
			http.Error(w, err.Error(), http.StatusBadGateway)
			return
		}

		committed.Store(true)
		if err := tx.Commit(); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.WriteHeader(http.StatusCreated)
	})
}

func processLongOrder(ctx context.Context, tx *sql.Tx) error { return nil }
func cleanupDistributedLease(ctx context.Context) error     { return nil }
```

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: Deterministic Resource Cleanup and Rollbacks with Chi v5 and context.AfterFunc

Deterministic Resource Cleanup and Rollbacks with Chi v5 and context.AfterFunc defines an industrial-grade behavioral standard for backend engineering. Enforces asynchronous, non-blocking distributed resource cancellation and database transaction rollbacks upon client connection termination (such as HTTP/3 QUIC stream resets) using Go 1.21+ `context.AfterFunc`. Prevents orphan lock retention, dangling distributed leases, and zombie worker routines when a client disconnects prior to HTTP handler completion in Chi v5 routers. 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: Relying Exclusively on Synchronous Defer Blocks and Epoll Context Checks in Handlers 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 DriftRelying Exclusively on Synchronous Defer Blocks and Epoll Context Checks in HandlersCritical
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 register an asynchronous teardown callback via `context.AfterFunc(r.Context(), ...)` for distributed locks, lease renewals, or external queue reservations immediately after acquisition.

Engineers MUST ALWAYS register an asynchronous teardown callback via `context.AfterFunc(r.Context(), ...)` for distributed locks, lease renewals, or external queue reservations immediately after acquisition.

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 ensure that any `stop()` function returned by `context.AfterFunc` is invoked in a standard `defer` block to dereference callbacks and prevent memory leaks upon normal handler completion.

Engineers MUST ensure that any `stop()` function returned by `context.AfterFunc` is invoked in a standard `defer` block to dereference callbacks and prevent memory leaks upon normal handler completion.

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 run blocking I/O directly inside the `context.AfterFunc` callback without spawning a detached goroutine protected by a bounded background context (`context.WithoutCancel`).

Engineers MUST NOT run blocking I/O directly inside the `context.AfterFunc` callback without spawning a detached goroutine protected by a bounded background context (`context.WithoutCancel`).

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

Services MUST orchestrate transactional aborts defensively, verifying whether a transaction is already committed before attempting an `AfterFunc`-triggered rollback.

Services MUST orchestrate transactional aborts defensively, verifying whether a transaction is already committed before attempting an `AfterFunc`-triggered rollback.

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 solely on polling `ctx.Done()` in deeply nested internal packages when external distributed leases must be yielded to other cluster nodes instantly upon HTTP/3 stream drops.

Components NEVER rely solely on polling `ctx.Done()` in deeply nested internal packages when external distributed leases must be yielded to other cluster nodes instantly upon HTTP/3 stream 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.
Technical Questions & Answers

Frequently Asked Technical Questions

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

Q:Why is Deterministic Resource Cleanup and Rollbacks with Chi v5 and context.AfterFunc critical for AI coding assistants?

Enforces asynchronous, non-blocking distributed resource cancellation and database transaction rollbacks upon client connection termination (such as HTTP/3 QUIC stream resets) using Go 1.21+ `context.AfterFunc`. Prevents orphan lock retention, dangling distributed leases, and zombie worker routines when a client disconnects prior to HTTP handler completion in Chi v5 routers. 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 (Relying Exclusively on Synchronous Defer Blocks and Epoll Context Checks in Handlers) 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

Deterministic