5c23db8885
pg.Cluster wraps a primary pool and an optional read-replica pool. Routing is explicit — Read(), Write(), Primary() — with no SQL inspection: statement text misroutes CTE writes and SELECT ... FOR UPDATE in both directions. An unhealthy replica falls back to the primary behind a ping-based circuit that retries on a doubling backoff window, and migrations always run through Write(). pg.ClusterDSNsFromEnv resolves both endpoints from the environment, naming the read-only host explicitly rather than deriving it from the primary's.
20 lines
572 B
Go
20 lines
572 B
Go
// Package pg holds the estate's shared Postgres plumbing: environment-driven
|
|
// DSN construction, pgxpool construction, read/write splitting across a primary
|
|
// and a read replica, and the migration runner every service uses to bring its
|
|
// own schema up to date at startup.
|
|
package pg
|
|
|
|
import (
|
|
"io"
|
|
"log/slog"
|
|
)
|
|
|
|
// logger returns log, or a logger that discards everything when log is nil, so
|
|
// callers may leave the option unset.
|
|
func logger(log *slog.Logger) *slog.Logger {
|
|
if log != nil {
|
|
return log
|
|
}
|
|
return slog.New(slog.NewTextHandler(io.Discard, nil))
|
|
}
|