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>
95 lines
2.1 KiB
Go
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:])
|
|
}
|