Architectural Invariant Design: Go Gin Clean Architecture & Explicit Error Handling
Enterprise Go microservices demand explicit error propagation, concurrency safety, and context propagation. In high-throughput Gin APIs, unbounded goroutine spawning without context timeouts or worker pools leads to file descriptor exhaustion and silent memory leaks.
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 Mode | AI Symptom (The Anti-Pattern) | Severity | Production Impact & Remedy |
|---|---|---|---|
| Unbounded Goroutine Leakage | AI creates background goroutines using `go func()` with the Gin context `c` directly | Critical | Gin context is recycled after the HTTP handler returns; reading `c` concurrently triggers race conditions and memory corruption. Never pass `*gin.Context` to background goroutines. Use `c.Copy()` or pass a bounded `context.WithTimeout(context.Background(), ...)`. |
| Swallowed Error Returns | AI ignores returned errors: `val, _ := db.Query()` | High | Hides database failures, causes silent data corruption, and prevents Prometheus error metric increments. Always check `if err != nil` and wrap errors with domain context using `fmt.Errorf("failed to query: %w", err)`. |
Step-by-Step Production Directives
Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:
Never ignore returned errors with blank identifier `_`. Check `if err != nil` and wrap with `fmt.Errorf("...
Never ignore returned errors with blank identifier `_`. Check `if err != nil` and wrap with `fmt.Errorf("...: %w", err)`.
Pass `c.Request.Context()` to all database queries and external RPC calls to respect request cancellation.
Pass `c.Request.Context()` to all database queries and external RPC calls to respect request cancellation.
Organize projects following Clean Architecture
Organize projects following Clean Architecture: handler -> service/usecase -> repository.
Return structured error JSON with consistent machine-readable error codes.
Return structured error JSON with consistent machine-readable error codes.
Frequently Asked Technical Questions
Common questions developers face when configuring AI coding assistants for this stack:
Q:Why should I not pass gin.Context to a goroutine?
Gin reuses `gin.Context` instances across HTTP requests via an internal sync.Pool to minimize memory allocations. If a goroutine retains a pointer to `gin.Context` after the response finishes, another incoming request will mutate that same context concurrently, resulting in catastrophic race conditions.
Q:How should database transactions be handled in Go clean architecture?
Pass `context.Context` through all service and repository layers, and manage the database transaction life-cycle with a `defer tx.Rollback()` pattern so unexpected panics or errors guarantee rollback.