This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: go-chi-v5-middleware-graceful-shutdown-production-standard

Go Chi v5 Middleware Isolation, Context Cancellation, and Signal-Driven Graceful Shutdown

Mandates deterministic HTTP lifecycle management in Go Chi v5 services through isolated sub-router middleware stacks, strict r.Context() propagation to downstream I/O, and non-blocking OS signal-trapping graceful shutdown. Prevents dropped in-flight requests, detached context goroutine leaks, and middleware leakage across sibling sub-routes.

Prohibited Anti-Pattern: Synchronous Server Blocking, Context Abandonment, and Leaky Sub-Router Middleware Hierarchies

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Go Chi v5 Middleware Isolation, Context Cancellation, and Signal-Driven Graceful Shutdown - Mandates deterministic HTTP lifecycle management in Go Chi v5 services through isolated sub-router middleware stacks, strict r.Context() propagation to downstream I/O, and non-blocking OS signal-trapping graceful shutdown. Prevents dropped in-flight requests, detached context goroutine leaks, and middleware leakage across sibling sub-routes.
globs: cmd/**/*.go, internal/**/*.go, pkg/**/*.go, main.go
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/go-chi-v5-middleware-graceful-shutdown-production-standard"
---

# Go Chi v5 Middleware Isolation, Context Cancellation, and Signal-Driven Graceful Shutdown

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Synchronous Server Blocking, Context Abandonment, and Leaky Sub-Router Middleware Hierarchies

## System Constraints
You are a Principal Software Architect enforcing production-grade Go Chi v5 standards. You must reject any HTTP server configuration that uses synchronous ListenAndServe on the main thread, fails to propagate r.Context() to all blocking operations, or uses unscoped global middleware that bleeds into independent sub-router domains.

## Strict Guidelines
- Services MUST execute http.Server.ListenAndServe in a dedicated goroutine and capture http.ErrServerClosed explicitly as a non-fatal exit status.
- Engineers MUST handle OS shutdown signals (SIGINT, SIGTERM) using signal.NotifyContext or a dedicated signal channel to execute srv.Shutdown(shutdownCtx) with an independent, bounded timeout context.
- Handlers and custom middlewares MUST ALWAYS thread r.Context() into all downstream database queries, external HTTP/gRPC calls, and asynchronous workers; engineers MUST NEVER pass context.Background() or context.TODO() into request-scoped I/O operations.
- Engineers MUST scope domain-specific middleware (e.g., Auth, RateLimiting, ContentType) using r.Route('/prefix', func(r chi.Router) { ... }) or r.Group instead of attaching them to the root chi.Mux where they inadvertently intercept health/metrics endpoints.
- When using chi/middleware.Timeout, handlers MUST explicitly monitor select { case <-ctx.Done(): ... } before executing critical state mutations to prevent orphaned writes after the client deadline expires.
- Custom middlewares MUST invoke next.ServeHTTP(w, r.WithContext(ctx)) with the mutated context when injecting request-scoped dependencies or values.
- The graceful shutdown flow MUST invoke server.Shutdown before draining external resource pools (database connections, message queues, cache clients) to ensure in-flight handlers finish successfully.

## Bad vs Good Implementations
### Graceful Server Lifecycle and Context-Aware Sub-Router Construction

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: 1. http.ListenAndServe runs synchronously on main, preventing graceful termination on SIGTERM and dropping active connections during deployments. 2. Auth middleware is mounted globally, leaking authentication checks onto the health-check endpoint. 3. Asynchronous handler logic detaches from r.Context() using context.Background(), causing database operations to continue running even if the client disconnects or times out.
```go
package main

import (
	"context"
	"database/sql"
	"net/http"
	"time"

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

func main() {
	r := chi.NewRouter()
	// Global middleware applied to all routes including public/health endpoints
	r.Use(middleware.Logger)
	r.Use(middleware.Timeout(5 * time.Second))
	r.Use(DummyAuthMiddleware) // Leaks into /healthz

	r.Get("/healthz", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	r.Post("/api/orders", func(w http.ResponseWriter, r *http.Request) {
		// Detaches from request context; ignores client cancellation/timeouts
		go processOrder(context.Background(), r)
		w.WriteHeader(http.StatusAccepted)
	})

	// Blocks the main goroutine; no signal trapping, abrupt termination drops active requests
	http.ListenAndServe(":8080", r)
}

func DummyAuthMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		next.ServeHTTP(w, r)
	})
}

func processOrder(ctx context.Context, r *http.Request) {
	// Database query uses detached context
	var db *sql.DB
	_ = db.PingContext(ctx)
}
```

#### Production Standard (Correct)
> **Standard**: 1. Uses signal.NotifyContext to catch SIGINT/SIGTERM cleanly and runs ListenAndServe in a goroutine while explicitly ignoring http.ErrServerClosed. 2. Configures a decoupled 15-second shutdown context to allow in-flight connections to drain. 3. Uses r.Route() to scope timeout and authentication middleware specifically to /api/v1, leaving the /healthz endpoint unhindered. 4. Propagates r.Context() to all I/O operations and validates ctx.Err() before mutating system state.
```go
package main

import (
	"context"
	"database/sql"
	"errors"
	"log/slog"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

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

func main() {
	logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
	rootCtx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
	defer stop()

	r := chi.NewRouter()
	r.Use(middleware.RequestID)
	r.Use(middleware.RealIP)
	r.Use(middleware.Recoverer)

	// Public unauthenticated routes
	r.Get("/healthz", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	// Scoped private sub-router
	r.Route("/api/v1", func(api chi.Router) {
		api.Use(middleware.Timeout(10 * time.Second))
		api.Use(DummyAuthMiddleware)

		api.Post("/orders", handleCreateOrder)
	})

	srv := &http.Server{
		Addr:              ":8080",
		Handler:           r,
		ReadHeaderTimeout: 5 * time.Second,
		IdleTimeout:       120 * time.Second,
	}

	srvErr := make(chan error, 1)
	go func() {
		logger.Info("starting http server", slog.String("addr", srv.Addr))
		if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			srvErr <- err
		}
	}()

	select {
	case err := <-srvErr:
		logger.Error("server failed to start", slog.Any("error", err))
	case <-rootCtx.Done():
		logger.Info("shutting down server gracefully")
		shutdownCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
		defer cancel()

		if err := srv.Shutdown(shutdownCtx); err != nil {
			logger.Error("forced shutdown triggered", slog.Any("error", err))
			_ = srv.Close()
		}
	}
}

func DummyAuthMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Inject values safely via r.WithContext(ctx)
		next.ServeHTTP(w, r)
	})
}

func handleCreateOrder(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	// Validate context is active prior to heavy state changes
	if err := ctx.Err(); err != nil {
		http.Error(w, "request timed out or canceled", http.StatusGatewayTimeout)
		return
	}
	// Downstream operations must inherit r.Context()
	var db *sql.DB
	if err := db.PingContext(ctx); err != nil {
		http.Error(w, "database unavailable", http.StatusServiceUnavailable)
		return
	}
	w.WriteHeader(http.StatusAccepted)
}
```

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: Go Chi v5 Middleware Isolation, Context Cancellation, and Signal-Driven Graceful Shutdown

Go Chi v5 Middleware Isolation, Context Cancellation, and Signal-Driven Graceful Shutdown defines an industrial-grade behavioral standard for backend engineering. Mandates deterministic HTTP lifecycle management in Go Chi v5 services through isolated sub-router middleware stacks, strict r.Context() propagation to downstream I/O, and non-blocking OS signal-trapping graceful shutdown. Prevents dropped in-flight requests, detached context goroutine leaks, and middleware leakage across sibling sub-routes. 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: Synchronous Server Blocking, Context Abandonment, and Leaky Sub-Router Middleware Hierarchies 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 DriftSynchronous Server Blocking, Context Abandonment, and Leaky Sub-Router Middleware HierarchiesCritical
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

Services MUST execute http.Server.ListenAndServe in a dedicated goroutine and capture http.ErrServerClosed explicitly as a non-fatal exit status.

Services MUST execute http.Server.ListenAndServe in a dedicated goroutine and capture http.ErrServerClosed explicitly as a non-fatal exit status.

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 handle OS shutdown signals (SIGINT, SIGTERM) using signal.NotifyContext or a dedicated signal channel to execute srv.Shutdown(shutdownCtx) with an independent, bounded timeout context.

Engineers MUST handle OS shutdown signals (SIGINT, SIGTERM) using signal.NotifyContext or a dedicated signal channel to execute srv.Shutdown(shutdownCtx) with an independent, bounded timeout context.

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

Handlers and custom middlewares MUST ALWAYS thread r.Context() into all downstream database queries, external HTTP/gRPC calls, and asynchronous workers

Handlers and custom middlewares MUST ALWAYS thread r.Context() into all downstream database queries, external HTTP/gRPC calls, and asynchronous workers; engineers MUST NEVER pass context.Background() or context.TODO() into request-scoped I/O operations.

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

Engineers MUST scope domain-specific middleware (e.g., Auth, RateLimiting, ContentType) using r.Route('/prefix', func(r chi.Router) { ... }) or r.Group instead of attaching them to the root chi.Mux where they inadvertently intercept health/metrics endpoints.

Engineers MUST scope domain-specific middleware (e.g., Auth, RateLimiting, ContentType) using r.Route('/prefix', func(r chi.Router) { ... }) or r.Group instead of attaching them to the root chi.Mux where they inadvertently intercept health/metrics endpoints.

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

When using chi/middleware.Timeout, handlers MUST explicitly monitor select { case <-ctx.Done()

When using chi/middleware.Timeout, handlers MUST explicitly monitor select { case <-ctx.Done(): ... } before executing critical state mutations to prevent orphaned writes after the client deadline expires.

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

Custom middlewares MUST invoke next.ServeHTTP(w, r.WithContext(ctx)) with the mutated context when injecting request-scoped dependencies or values.

Custom middlewares MUST invoke next.ServeHTTP(w, r.WithContext(ctx)) with the mutated context when injecting request-scoped dependencies or values.

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

The graceful shutdown flow MUST invoke server.Shutdown before draining external resource pools (database connections, message queues, cache clients) to ensure in-flight handlers finish successfully.

The graceful shutdown flow MUST invoke server.Shutdown before draining external resource pools (database connections, message queues, cache clients) to ensure in-flight handlers finish successfully.

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 Go Chi v5 Middleware Isolation, Context Cancellation, and Signal-Driven Graceful Shutdown critical for AI coding assistants?

Mandates deterministic HTTP lifecycle management in Go Chi v5 services through isolated sub-router middleware stacks, strict r.Context() propagation to downstream I/O, and non-blocking OS signal-trapping graceful shutdown. Prevents dropped in-flight requests, detached context goroutine leaks, and middleware leakage across sibling sub-routes. 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 (Synchronous Server Blocking, Context Abandonment, and Leaky Sub-Router Middleware Hierarchies) 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

Go