This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This project uses mise for tooling. All commands should be run via mise run:
mise run all # Format, lint, and test (full CI pipeline)
mise run test # Run tests with gotestsum (auto-reruns failures)
mise run lint # Run golangci-lint with --fix
mise run format # Run go fmt
mise run tidy # Update dependencies and run go mod tidyTo run a single test:
go test -run TestIsTransient -vretrypool is a drop-in wrapper around pgxpool.Pool that adds automatic retry with exponential backoff for transient PostgreSQL errors.
-
Pool(retrypool.go) - Wraps*pgxpool.Pooland implements the DBTX interface (Exec,Query,QueryRow) expected by sqlc-generated code. Each method retries on transient errors. -
retryRow(retry.go) - Wrapspgx.Rowto handle retry inQueryRow. This is needed becausepgx.Row.Scan()has no context parameter, so the context must be stored in the struct (hence the//nolint:containedctxdirective). -
IsTransient()(retry.go) - Determines if an error is safe to retry. Checks:pgconn.SafeToRetry()- query never sent to server- Network errors (timeouts, connection refused/reset, broken pipe)
- PostgreSQL error codes: 08xxx (connection exceptions), 57P01/57P02/57P03 (admin/crash shutdown)
- Error message patterns as fallback
- Exponential backoff:
baseDelay * 2^attempt - 25% jitter to prevent thundering herd
- Maximum delay capped at 5 seconds
- Context cancellation respected during waits
- Defaults: 3 retries, 100ms base delay
This library is designed primarily for read operations. While pgconn.SafeToRetry() prevents retrying queries already sent to the server, edge cases exist where a write succeeds but the connection fails before client confirmation.
Safe: SELECT queries, idempotent writes, writes with unique constraints
Caution: Non-idempotent INSERTs, incremental updates (balance = balance + 100)
For critical non-idempotent writes, use rp.Pool() directly or wrap in a transaction.
pool, _ := pgxpool.New(ctx, connString)
rp := retrypool.New(pool, retrypool.WithMaxRetries(5))
// rp is now usable as a DBTX for sqlcUses golangci-lint with a strict configuration (.golangci.yml). Notable enabled linters:
containedctx- warns about storing context in structs (explicitly allowed inretryRow)wsl_v5- enforces whitespace styleexhaustive- requires exhaustive switch statements