Documentation
¶
Overview ¶
Package postgres provides PostgreSQL connection, migration, and metrics infrastructure. The composition root owns the *pgxpool.Pool; the functions here borrow it and never close it.
Index ¶
- Constants
- Variables
- func ClosePool(pool *pgxpool.Pool, timeout time.Duration) error
- func Migrate(ctx context.Context, pool *pgxpool.Pool, logger *zap.Logger, ...) error
- func MigrationStatus(ctx context.Context, pool *pgxpool.Pool, migrationFS embed.FS) (database.MigrationStatus, error)
- func NewPool(ctx context.Context, uri string, poolCfg PoolConfig) (*pgxpool.Pool, error)
- func Ping(ctx context.Context, pool *pgxpool.Pool, timeout time.Duration) error
- type PoolCollector
- type PoolConfig
Constants ¶
const (
// DefaultPingTimeoutSeconds is the default timeout for database ping operations
DefaultPingTimeoutSeconds = 15
)
Variables ¶
var Migrations embed.FS
Migrations holds the embedded, forward-only SQL migrations applied by Client.Migrate at startup. It is the same directory sqlc reads its schema from (see sqlc.yaml), so the generated types and the live schema share a single source of truth.
Functions ¶
func ClosePool ¶
ClosePool closes the pool, bounding the wait by timeout. pgxpool.Pool.Close blocks until every connection is returned to the pool and closed, so a connection wedged mid-query (or on a dead socket) can otherwise hang shutdown indefinitely. On timeout ClosePool stops waiting and returns an error; the abandoned Close finishes on its own if it can make progress, and the process is exiting regardless. It returns nil once Close completes within the timeout. A non-positive timeout waits indefinitely (the raw Close behaviour).
func Migrate ¶
func Migrate(ctx context.Context, pool *pgxpool.Pool, logger *zap.Logger, migrationFS embed.FS) error
Migrate applies all pending, forward-only migrations from the embedded filesystem. goose tracks applied migrations by numeric version in its own table and runs each inside its own transaction. It is safe to call on every invocation: already-applied versions are skipped and a fully-migrated database is a no-op. A PostgreSQL session advisory lock serializes concurrent callers. Applied migrations are logged through logger; a nil logger discards them.
goose keys purely on the version number and does not checksum migration bodies, so editing an already-applied file is silently ignored — change the schema by adding a new versioned migration, never by editing an applied one.
func MigrationStatus ¶
func MigrationStatus(ctx context.Context, pool *pgxpool.Pool, migrationFS embed.FS) (database.MigrationStatus, error)
MigrationStatus reports whether all, some, or none of the embedded migrations have been applied. It derives the coarse database.MigrationStatus from goose's per-migration status list.
It is not strictly read-only: querying status ensures goose's version table exists, so calling it against a pristine database creates that table (with no migration rows). Keep this in mind before wiring it into a readiness probe.
func NewPool ¶
NewPool parses the connection URI and returns a pgx pool configured with the supplied tuning knobs. Building the pool through ParseConfig + NewWithConfig (rather than pgxpool.New) is what lets callers size the pool explicitly instead of inheriting the all-default settings, which are frequently wrong under load. The pool connects lazily; callers should Ping before serving to surface an unreachable database at startup.
Types ¶
type PoolCollector ¶
type PoolCollector struct {
// contains filtered or unexported fields
}
PoolCollector is a prometheus.Collector that exposes pgxpool connection-pool statistics. It reads pool.Stat() lazily on every scrape rather than sampling on a timer, so each /metrics scrape reflects the pool's live state with no background goroutine to manage or leak.
Surfacing acquired/idle/total counts alongside the empty-acquire and canceled-acquire counters makes connection-pool saturation visible before it manifests as query timeouts: a rising empty-acquire count with acquired pinned at max is exhaustion.
func NewPoolCollector ¶
func NewPoolCollector(pool *pgxpool.Pool) *PoolCollector
NewPoolCollector builds a collector reading from the supplied pool. Register it on a Prometheus registry (typically prometheus.MustRegister so it is exposed by the same /metrics handler as the rest of the server's metrics).
func (*PoolCollector) Collect ¶
func (c *PoolCollector) Collect(ch chan<- prometheus.Metric)
Collect implements prometheus.Collector. It takes a single stats snapshot per scrape so every metric in the scrape is internally consistent.
func (*PoolCollector) Describe ¶
func (c *PoolCollector) Describe(ch chan<- *prometheus.Desc)
Describe implements prometheus.Collector.
type PoolConfig ¶
type PoolConfig struct {
// MaxConns caps the pool size. 0 keeps the pgx default (the greater of 4
// and runtime.NumCPU()).
MaxConns int
// MinConns is the number of idle connections the pool keeps warm. 0 keeps
// the pgx default (0).
MinConns int
// MaxConnLifetimeSeconds closes and replaces a connection this long after
// it was created. 0 keeps the pgx default (1 hour).
MaxConnLifetimeSeconds int
// MaxConnIdleTimeSeconds closes a connection that has been idle this long.
// 0 keeps the pgx default (30 minutes).
MaxConnIdleTimeSeconds int
// HealthCheckPeriodSeconds is the interval between pool health checks of
// idle connections. 0 keeps the pgx default (1 minute).
HealthCheckPeriodSeconds int
}
PoolConfig carries the connection-pool tuning knobs applied on top of the settings parsed from the connection URI. Every field is optional: a zero value leaves the corresponding pgx default in place, so callers only set the knobs they care about. Counts are plain integers; durations are expressed in seconds to match the surrounding config surface.
func PoolConfigFromDatabase ¶
func PoolConfigFromDatabase(cfg config.Database) PoolConfig
PoolConfigFromDatabase maps the database configuration section onto the pool tuning knobs. Every composition root (serve, seed, migrate) sizes its pool through this one mapping so a new knob cannot be wired into one command and silently left at the pgx default in another.