Files
dbx/config.go
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

95 lines
2.1 KiB
Go

package dbx
import (
"time"
"github.com/jackc/pgx/v5"
)
// Config is the top-level configuration for a Cluster.
type Config struct {
Master NodeConfig
Replicas []NodeConfig
Retry RetryConfig
Logger Logger
Metrics *MetricsHook
HealthCheck HealthCheckConfig
SlowQueryThreshold time.Duration
}
// NodeConfig describes a single database node.
type NodeConfig struct {
Name string // human-readable name for logs/metrics, e.g. "master", "replica-1"
DSN string
Pool PoolConfig
Tracer pgx.QueryTracer
}
// PoolConfig controls pgxpool.Pool parameters.
type PoolConfig struct {
MaxConns int32
MinConns int32
MaxConnLifetime time.Duration
MaxConnIdleTime time.Duration
HealthCheckPeriod time.Duration
}
// RetryConfig controls retry behaviour.
type RetryConfig struct {
MaxAttempts int // default: 3
BaseDelay time.Duration // default: 50ms
MaxDelay time.Duration // default: 1s
RetryableErrors func(error) bool // optional custom classifier
}
// HealthCheckConfig controls the background health checker.
type HealthCheckConfig struct {
Interval time.Duration // default: 5s
Timeout time.Duration // default: 2s
}
// defaults fills zero-valued fields with sensible defaults.
func (c *Config) defaults() {
if c.Logger == nil {
c.Logger = nopLogger{}
}
if c.Retry.MaxAttempts <= 0 {
c.Retry.MaxAttempts = 3
}
if c.Retry.BaseDelay <= 0 {
c.Retry.BaseDelay = 50 * time.Millisecond
}
if c.Retry.MaxDelay <= 0 {
c.Retry.MaxDelay = time.Second
}
if c.HealthCheck.Interval <= 0 {
c.HealthCheck.Interval = 5 * time.Second
}
if c.HealthCheck.Timeout <= 0 {
c.HealthCheck.Timeout = 2 * time.Second
}
if c.Master.Name == "" {
c.Master.Name = "master"
}
for i := range c.Replicas {
if c.Replicas[i].Name == "" {
c.Replicas[i].Name = "replica-" + itoa(i+1)
}
}
}
// itoa is a minimal int-to-string without importing strconv.
func itoa(n int) string {
if n == 0 {
return "0"
}
buf := [20]byte{}
i := len(buf)
for n > 0 {
i--
buf[i] = byte('0' + n%10)
n /= 10
}
return string(buf[i:])
}