Help us shape the future of Go! Take the 2026 Go Developer Survey

postgres

package
v0.0.0-...-641ec4a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 14 Imported by: 0

README

PostgreSQL infrastructure

This package owns the service's PostgreSQL connection pool construction, the bounded ping and close lifecycle, Prometheus pool metrics, and embedded Goose migrations, all as functions over a caller-owned *pgxpool.Pool. Migration application holds Goose's PostgreSQL session advisory lock, so concurrent callers serialize. Application and CLI composition roots construct the pool and retain responsibility for closing it.

It does not own business models, repository behavior, authentication, or HTTP mapping. Those contracts live in internal/domain, and the example user repository lives in internal/modules/user.

Structure

  • migrations/ contains sequential Goose migrations embedded into the binary. Add schema changes as new migrations; do not rewrite an applied migration.
  • queries/ contains fixed SQL statements consumed by sqlc.
  • db/ is generated by sqlc and must not be edited directly. Only PostgreSQL infrastructure and the owning user module may import it.
  • The parent internal/platform/database package contains the technical migration-status contract shared with lifecycle consumers.

Run make migration name=<name> to scaffold a migration. After changing migrations or queries, run make generate and commit the resulting db/ output. make generate-check verifies that generated SQL remains current. Apply the embedded set explicitly with go run . migrate up; inspect it with go run . migrate status.

See the golang-database skill for transaction, sqlc-versus-squirrel, testing, and migration guidance.

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

View Source
const (
	// DefaultPingTimeoutSeconds is the default timeout for database ping operations
	DefaultPingTimeoutSeconds = 15
)

Variables

View Source
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

func ClosePool(pool *pgxpool.Pool, timeout time.Duration) error

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

func NewPool(ctx context.Context, uri string, poolCfg PoolConfig) (*pgxpool.Pool, error)

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.

func Ping

func Ping(ctx context.Context, pool *pgxpool.Pool, timeout time.Duration) error

Ping verifies the pool can reach the database. A positive timeout bounds the attempt; zero or negative defers entirely to the caller's context.

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.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL