Some checks failed
CI / test (push) Failing after 13s
- 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>
59 lines
2.9 KiB
Plaintext
59 lines
2.9 KiB
Plaintext
You are working on `git.codelab.vc/pkg/dbx`, a Go PostgreSQL cluster library built on pgx/v5.
|
|
|
|
## Architecture
|
|
|
|
- Cluster manages master + replicas with method-based routing (no SQL parsing)
|
|
- Write ops (Exec, Query, QueryRow, Begin, BeginTx, CopyFrom, SendBatch) → master
|
|
- Read ops (ReadQuery, ReadQueryRow) → replicas with master fallback
|
|
- Retry with exponential backoff + jitter, iterates nodes then backs off
|
|
- Round-robin balancer skips unhealthy nodes
|
|
- Background health checker pings all nodes on interval
|
|
- RunTx — panic-safe transaction wrapper (recover → rollback → re-panic)
|
|
- InjectQuerier/ExtractQuerier — context-based Querier for service layers
|
|
|
|
## Package structure
|
|
|
|
- `dbx` (root) — Cluster, Node, Balancer, retry, health, errors, tx, config, options
|
|
- `dbx.go` — interfaces: Querier, DB, Logger, MetricsHook
|
|
- `cluster.go` — Cluster routing and query execution
|
|
- `node.go` — Node wrapping pgxpool.Pool with health state
|
|
- `balancer.go` — Balancer interface + RoundRobinBalancer
|
|
- `retry.go` — retrier with backoff and node fallback
|
|
- `health.go` — background health checker goroutine
|
|
- `tx.go` — RunTx, RunTxOptions, InjectQuerier, ExtractQuerier
|
|
- `errors.go` — IsRetryable, IsConnectionError, IsConstraintViolation, PgErrorCode
|
|
- `config.go` — Config, NodeConfig, PoolConfig, RetryConfig, HealthCheckConfig
|
|
- `options.go` — functional options (WithLogger, WithMetrics, WithRetry, WithHealthCheck, WithSlowQueryThreshold, WithTracer)
|
|
- `slog.go` — SlogLogger adapting *slog.Logger to dbx.Logger
|
|
- `scan.go` — Collect[T], CollectOne[T] generic row scan helpers
|
|
- `stats.go` — PoolStats aggregate pool statistics via Cluster.Stats()
|
|
- `dbxtest/` — test helpers: NewTestCluster, TestLogger, RunInTx
|
|
|
|
## Code conventions
|
|
|
|
- Struct-based Config with defaults() method for zero-value defaults
|
|
- Functional options (Option func(*Config)) used via ApplyOptions
|
|
- stdlib only testing — no testify, no gomock
|
|
- Thread safety with atomic.Bool (Node.healthy, Cluster.closed)
|
|
- dbxtest.NewTestCluster skips on unreachable DB, auto-closes via t.Cleanup
|
|
- Sentinel errors: ErrNoHealthyNode, ErrClusterClosed, ErrRetryExhausted
|
|
- retryError multi-unwrap for errors.Is compatibility
|
|
|
|
## When writing new code
|
|
|
|
- New node type → add to Cluster struct, Config, connect in NewCluster, add to `all` for health checking
|
|
- New balancer → implement Balancer interface, check IsHealthy(), return nil if no suitable node
|
|
- New retry logic → provide RetryConfig.RetryableErrors or extend IsRetryable()
|
|
- New metrics hook → add field to MetricsHook, nil-check before calling
|
|
- Close() is required — leaking a Cluster leaks goroutines and connections
|
|
- No SQL parsing — routing is method-based, Exec with SELECT still goes to master
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
go build ./... # compile
|
|
go test ./... # test
|
|
go test -race ./... # test with race detector
|
|
go vet ./... # static analysis
|
|
```
|