Files
dbx/CLAUDE.md
Aleksey Shakhmatov 2c9af28548
Some checks failed
CI / test (push) Failing after 13s
Add production features: slog adapter, scan helpers, slow query logging, pool stats, tracer passthrough, test tx isolation
- slog.go: SlogLogger adapts *slog.Logger to dbx.Logger interface
- scan.go: Collect[T] and CollectOne[T] generic helpers using pgx.RowToStructByName
- cluster.go: slow query logging via Config.SlowQueryThreshold (Warn level in queryEnd)
- stats.go: PoolStats with Cluster.Stats() aggregating pool stats across all nodes
- config.go/node.go: NodeConfig.Tracer passthrough for pgx.QueryTracer (OpenTelemetry)
- options.go: WithSlowQueryThreshold and WithTracer functional options
- dbxtest/tx.go: RunInTx runs callback in always-rolled-back transaction for test isolation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 00:19:26 +03:00

54 lines
2.9 KiB
Markdown

# CLAUDE.md — dbx
## Commands
```bash
go build ./... # compile
go test ./... # all tests
go test -race ./... # tests with race detector
go test -v -run TestName ./... # single test
go vet ./... # static analysis
```
## Architecture
- **Module**: `git.codelab.vc/pkg/dbx`, Go 1.24, depends on pgx/v5
- **Single package** `dbx` (+ `dbxtest` for test helpers)
### Core patterns
- **Cluster** is the entry point — connects master + replicas, routes writes to master, reads to replicas with master fallback
- **Routing is method-based**: `Exec`/`Query`/`QueryRow`/`Begin`/`BeginTx`/`CopyFrom`/`SendBatch` → master; `ReadQuery`/`ReadQueryRow` → replicas
- **Retry** with exponential backoff + jitter, node fallback; retrier.do() iterates nodes then backs off
- **Balancer** interface (`Next([]*Node) *Node`) — built-in `RoundRobinBalancer` skips unhealthy nodes
- **Health checker** — background goroutine pings all nodes on an interval, flips `Node.healthy` atomic bool
- **RunTx** — panic-safe transaction wrapper: recovers panics, rolls back, re-panics
- **Querier injection** — `InjectQuerier`/`ExtractQuerier` pass `Querier` via context for service layers
- **SlogLogger** — adapts `*slog.Logger` to the `dbx.Logger` interface (`slog.go`)
- **Collect/CollectOne** — generic scan helpers using `pgx.RowToStructByName` (`scan.go`)
- **Slow query logging** — `Config.SlowQueryThreshold` triggers Warn-level logging in `queryEnd`
- **PoolStats** — `Cluster.Stats()` aggregates pool statistics across all nodes (`stats.go`)
- **Tracer passthrough** — `NodeConfig.Tracer` / `WithTracer` sets `pgx.QueryTracer` for OpenTelemetry
- **RunInTx** — test helper that runs a callback in an always-rolled-back transaction (`dbxtest/tx.go`)
### Error classification
- `IsRetryable(err)` — connection errors (class 08), serialization failures (40001), deadlocks (40P01), too_many_connections (53300)
- `IsConnectionError(err)` — PG class 08 + string matching for pgx-wrapped errors
- `IsConstraintViolation(err)` — PG class 23
- `PgErrorCode(err)` — extract raw code from `*pgconn.PgError`
## Conventions
- Struct-based `Config` with `defaults()` method (not functional options for NewCluster constructor, but `Option` type exists for `ApplyOptions` in tests)
- Functional options (`Option func(*Config)`) used via `ApplyOptions` (e.g., in dbxtest)
- stdlib-only tests — no testify, no gomock
- `atomic.Bool` for thread safety (`Node.healthy`, `Cluster.closed`)
- `dbxtest.NewTestCluster` skips tests when DB unreachable, auto-closes via `t.Cleanup`
- `dbxtest.TestLogger` writes to `testing.T` for test log output
- `dbxtest.RunInTx` runs a callback in a transaction that is always rolled back
## See also
- `AGENTS.md` — universal AI agent guide with common tasks, gotchas, and ASCII diagrams