All checks were successful
CI / test (push) Successful in 51s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
56 lines
2.7 KiB
Plaintext
56 lines
2.7 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)
|
|
- `dbxtest/` — test helpers: NewTestCluster, TestLogger
|
|
|
|
## 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
|
|
```
|