postgres

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2026 License: MIT Imports: 13 Imported by: 0

README

go-postgres

go-postgres is focused production infrastructure for PostgreSQL applications built directly on pgx/v5. It standardizes finite pool configuration, bounded lifecycle operations, transaction cleanup, SQLSTATE classification, health, safe telemetry, and real PostgreSQL testing without hiding native pgx types.

It is not a driver, ORM, query builder, migration engine, repository layer, or multi-database abstraction.

Requirements

  • Go 1.25 or 1.26
  • pgx 5.10.x
  • PostgreSQL 14, 15, 16, 17, or 18
  • Docker-compatible container runtime only for postgrestest and integration tests

Quick start

ctx := context.Background()
pool, err := postgres.New(ctx, postgres.Config{
    DSN:             os.Getenv("DATABASE_URL"),
    MaxConns:        20,
    AcquireTimeout:  2 * time.Second,
    PingTimeout:     time.Second,
    ShutdownTimeout: 10 * time.Second,
})
if err != nil {
    return err
}
defer pool.Close(context.Background())

err = postgres.RunTransaction(ctx, pool.Raw(), postgres.TransactionOptions{
    TxOptions: pgx.TxOptions{IsoLevel: pgx.Serializable},
}, func(ctx context.Context, tx pgx.Tx) error {
    _, err := tx.Exec(ctx, "INSERT INTO jobs (name) VALUES ($1)", "reindex")
    return err
})

New performs a bounded startup ping by default. Pool.Raw() returns the exact *pgxpool.Pool, so generated sqlc code and all native pgx operations remain available.

Safe defaults

Setting Default
connect timeout 5 seconds
acquire timeout 5 seconds
ping timeout 2 seconds
shutdown timeout 10 seconds
maximum connections 10
maximum connection lifetime 1 hour
lifetime jitter 5 minutes
maximum idle time 30 minutes
health-check period 1 minute
startup policy fail-fast ping

Zero values select these defaults. Every limit is overrideable. TLS remains an explicit deployment decision: use a DSN with sslmode=verify-full or provide a verified tls.Config with TLSRequire; never assume encryption authenticates the server when InsecureSkipVerify is enabled.

Packages

  • root: configuration, pool lifecycle, transactions, health, classification, bounded observations, and safe slog integration
  • otelpostgres: optional standard OpenTelemetry metrics adapter
  • postgrestest: optional Testcontainers lifecycle helpers for real PostgreSQL

Query tracing is provided by go-telemetry/instrumentation/gopostgres through the native pgx.ConnConfig.Tracer hook. It records allow-listed query names and never SQL or arguments.

Documentation

Start with the documentation index, quickstart, and API reference. Operators should read the pool and lifecycle guide, TLS guide, Kubernetes guide, and operational FAQ.

Development

make safety
make integration
make check

make coverage proves exact 100% production statement coverage with a real PostgreSQL container. CI runs the integration suite on every supported PostgreSQL major version.

License

MIT. See LICENSE and THIRD_PARTY_NOTICES.md.

Documentation

Overview

Package postgres provides production infrastructure helpers around pgx and pgxpool without hiding their native types or behavior.

Index

Constants

View Source
const (
	// DefaultConnectTimeout bounds each new PostgreSQL connection attempt.
	DefaultConnectTimeout = 5 * time.Second
	// DefaultAcquireTimeout bounds waiting for a pooled connection.
	DefaultAcquireTimeout = 5 * time.Second
	// DefaultPingTimeout bounds startup and readiness probes.
	DefaultPingTimeout = 2 * time.Second
	// DefaultShutdownTimeout bounds how long Close waits for borrowed connections.
	DefaultShutdownTimeout = 10 * time.Second
)
View Source
const (
	// DefaultTransactionCleanupTimeout bounds rollback after cancellation.
	DefaultTransactionCleanupTimeout = 5 * time.Second
)

Variables

View Source
var (
	// ErrAcquireTimeout identifies the configured acquisition deadline.
	ErrAcquireTimeout = errors.New("postgres: acquire timeout")
	// ErrPoolExhausted identifies an acquisition timeout observed while all
	// configured connection slots were acquired or constructing.
	ErrPoolExhausted = errors.New("postgres: pool exhausted")
	// ErrHealthTimeout identifies a configured or caller health-check deadline.
	ErrHealthTimeout = errors.New("postgres: health check timeout")
	// ErrPoolClosed identifies a pool whose shutdown has begun.
	ErrPoolClosed = errors.New("postgres: pool closed")
	// ErrShutdownTimeout identifies a shutdown that outlasted its context.
	ErrShutdownTimeout = errors.New("postgres: shutdown timeout")
)
View Source
var (
	// ErrNilTransactionCallback reports a missing transaction body.
	ErrNilTransactionCallback = errors.New("postgres: transaction callback is nil")
)

Functions

func IsCancellation

func IsCancellation(err error) bool

IsCancellation reports caller context cancellation.

func IsCheckViolation

func IsCheckViolation(err error) bool

IsCheckViolation reports SQLSTATE 23514.

func IsConnectivity

func IsConnectivity(err error) bool

IsConnectivity reports PostgreSQL connection-class or network errors.

func IsDeadlock

func IsDeadlock(err error) bool

IsDeadlock reports SQLSTATE 40P01.

func IsExclusionViolation

func IsExclusionViolation(err error) bool

IsExclusionViolation reports SQLSTATE 23P01.

func IsForeignKeyViolation

func IsForeignKeyViolation(err error) bool

IsForeignKeyViolation reports SQLSTATE 23503.

func IsKind

func IsKind(err error, kind ErrorKind) bool

IsKind reports whether err classifies as kind.

func IsLockUnavailable

func IsLockUnavailable(err error) bool

IsLockUnavailable reports SQLSTATE 55P03. The state alone does not distinguish NOWAIT from lock_timeout.

func IsPoolExhaustion

func IsPoolExhaustion(err error) bool

IsPoolExhaustion reports a bounded acquisition timeout.

func IsQueryCanceled

func IsQueryCanceled(err error) bool

IsQueryCanceled reports SQLSTATE 57014. The state alone does not distinguish explicit cancellation from statement_timeout.

func IsRetryable

func IsRetryable(err error) bool

IsRetryable is advisory classification only. It never executes or retries a closure because callers must account for external side effects themselves.

func IsSerializationFailure

func IsSerializationFailure(err error) bool

IsSerializationFailure reports SQLSTATE 40001.

func IsTimeout

func IsTimeout(err error) bool

IsTimeout reports a context deadline.

func IsUniqueViolation

func IsUniqueViolation(err error) bool

IsUniqueViolation reports SQLSTATE 23505.

func RunSavepoint

func RunSavepoint(
	ctx context.Context,
	parent pgx.Tx,
	cleanupTimeout time.Duration,
	fn func(context.Context, pgx.Tx) error,
) error

RunSavepoint executes fn in pgx's explicit pseudo-nested transaction. pgx implements this with SAVEPOINT, RELEASE SAVEPOINT, and ROLLBACK TO SAVEPOINT.

func RunSavepointWithOptions

func RunSavepointWithOptions(
	ctx context.Context,
	parent pgx.Tx,
	options SavepointOptions,
	fn func(context.Context, pgx.Tx) error,
) (err error)

RunSavepointWithOptions executes fn in an observed pgx pseudo-nested transaction with bounded rollback cleanup.

func RunTransaction

func RunTransaction(
	ctx context.Context,
	beginner Beginner,
	options TransactionOptions,
	fn func(context.Context, pgx.Tx) error,
) (err error)

RunTransaction begins a transaction, invokes fn once, and finalizes exactly once. It never retries fn. Callback and rollback errors are joined so callers can inspect both with errors.Is and errors.As.

func SQLState

func SQLState(err error) (string, bool)

SQLState returns the first native PostgreSQL SQLSTATE in the error graph.

Types

type Beginner

type Beginner interface {
	BeginTx(context.Context, pgx.TxOptions) (pgx.Tx, error)
}

Beginner is implemented by pgx.Conn, pgxpool.Pool, pgxpool.Conn, and other native pgx values that can begin a transaction with explicit options.

type Config

type Config struct {
	DSN string

	ConnectTimeout  time.Duration
	AcquireTimeout  time.Duration
	PingTimeout     time.Duration
	ShutdownTimeout time.Duration

	MaxConns     int32
	MinConns     int32
	MinIdleConns int32

	MaxConnLifetime       time.Duration
	MaxConnLifetimeJitter time.Duration
	MaxConnIdleTime       time.Duration
	HealthCheckPeriod     time.Duration
	StartupPolicy         StartupPolicy
	TLS                   TLSConfig
	Observer              Observer

	// SessionInit runs for every newly established connection after any native
	// AfterConnect hook. Returning an error rejects that connection.
	SessionInit func(context.Context, *pgx.Conn) error

	// Configure receives the parsed native configuration after typed options
	// are applied and before the pool is created.
	Configure func(*PoolConfig) error
}

Config defines safe, finite defaults for constructing a PostgreSQL pool. Zero values select the documented defaults. Negative sizes or durations are rejected rather than passed through to pgxpool.

type ConfigError

type ConfigError struct {
	Field   string
	Problem string
	Cause   error
}

ConfigError reports a configuration field without echoing the DSN or its credentials. Cause is retained only for errors outside DSN parsing.

func (*ConfigError) Error

func (e *ConfigError) Error() string

Error implements error.

func (*ConfigError) Unwrap

func (e *ConfigError) Unwrap() error

Unwrap exposes a safe underlying cause when one is available.

type ErrorInfo

type ErrorInfo struct {
	Kind      ErrorKind
	SQLState  string
	Retryable bool
	Cause     error
	Postgres  *pgconn.PgError

	Severity   string
	Constraint string
	Schema     string
	Table      string
	Column     string
	Detail     string
	Hint       string
}

ErrorInfo classifies an error without replacing it. Cause is the exact input error, Postgres is the matched native PgError, and server metadata remains available for policy code that is allowed to inspect it.

func Classify

func Classify(err error) ErrorInfo

Classify returns stable policy metadata while preserving the original error graph for errors.Is and errors.As. Detail and Hint may contain sensitive values and must not be logged without an application redaction policy.

type ErrorKind

type ErrorKind string

ErrorKind is a stable policy category derived from an original error.

const (
	// ErrorNone is the classification of a nil error.
	ErrorNone ErrorKind = ""
	// ErrorUnknown indicates that no supported category matched.
	ErrorUnknown ErrorKind = "unknown"
	// ErrorUniqueViolation identifies SQLSTATE 23505.
	ErrorUniqueViolation ErrorKind = "unique_violation"
	// ErrorForeignKeyViolation identifies SQLSTATE 23503.
	ErrorForeignKeyViolation ErrorKind = "foreign_key_violation"
	// ErrorCheckViolation identifies SQLSTATE 23514.
	ErrorCheckViolation ErrorKind = "check_violation"
	// ErrorExclusionViolation identifies SQLSTATE 23P01.
	ErrorExclusionViolation ErrorKind = "exclusion_violation"
	// ErrorSerializationFailure identifies SQLSTATE 40001.
	ErrorSerializationFailure ErrorKind = "serialization_failure"
	// ErrorDeadlock identifies SQLSTATE 40P01.
	ErrorDeadlock ErrorKind = "deadlock"
	// ErrorTimeout identifies context deadlines.
	ErrorTimeout ErrorKind = "timeout"
	// ErrorCancellation identifies caller context cancellation.
	ErrorCancellation ErrorKind = "cancellation"
	// ErrorQueryCanceled identifies SQLSTATE 57014. PostgreSQL uses it for
	// explicit cancellation and statement_timeout, so policy must inspect its
	// own operation context rather than assume one cause.
	ErrorQueryCanceled ErrorKind = "query_canceled"
	// ErrorLockUnavailable identifies SQLSTATE 55P03. PostgreSQL uses it for
	// both NOWAIT and lock_timeout failures.
	ErrorLockUnavailable ErrorKind = "lock_unavailable"
	// ErrorConnectivity identifies connection-class and network errors.
	ErrorConnectivity ErrorKind = "connectivity"
	// ErrorPoolExhaustion identifies a bounded pool acquisition timeout.
	ErrorPoolExhaustion ErrorKind = "pool_exhaustion"
)

type Health

type Health struct {
	Ready bool
	Err   error
	Stats Stats
}

Health is the result of a readiness probe and its contemporaneous stats.

type Observation

type Observation struct {
	Operation Operation
	Outcome   Outcome
	Duration  time.Duration
	ErrorKind ErrorKind
	SQLState  string
	Pool      Stats
	// HasPoolStats distinguishes an actual zero-valued snapshot from an
	// operation, such as a transaction, that did not sample pool state.
	HasPoolStats bool
}

Observation contains bounded metadata only. It intentionally excludes SQL, query arguments, DSNs, database error text, and arbitrary caller labels.

type Observer

type Observer interface {
	Observe(context.Context, Observation)
}

Observer consumes bounded lifecycle and transaction observations.

func NewSlogObserver

func NewSlogObserver(logger *slog.Logger) Observer

NewSlogObserver creates a privacy-preserving Observer compatible with slog and go-log. It records only fixed operation metadata and pool gauges.

type ObserverFunc

type ObserverFunc func(context.Context, Observation)

ObserverFunc adapts a function to Observer.

func (ObserverFunc) Observe

func (f ObserverFunc) Observe(ctx context.Context, observation Observation)

Observe implements Observer.

type Operation

type Operation string

Operation is a fixed low-cardinality operation name.

const (
	// OperationAcquire identifies pool connection acquisition.
	OperationAcquire Operation = "pool.acquire"
	// OperationPing identifies pool health checks.
	OperationPing Operation = "pool.ping"
	// OperationClose identifies bounded pool shutdown waits.
	OperationClose Operation = "pool.close"
	// OperationTransaction identifies top-level transactions.
	OperationTransaction Operation = "transaction"
	// OperationSavepoint identifies explicit nested savepoints.
	OperationSavepoint Operation = "savepoint"
)

type Outcome

type Outcome string

Outcome is a fixed low-cardinality operation result.

const (
	// OutcomeSuccess indicates a nil operation error.
	OutcomeSuccess Outcome = "success"
	// OutcomeError indicates a classified operation error.
	OutcomeError Outcome = "error"
	// OutcomePanic indicates that a transaction callback panicked.
	OutcomePanic Outcome = "panic"
)

type Pool

type Pool struct {
	// contains filtered or unexported fields
}

Pool adds bounded lifecycle operations while retaining the native pgxpool.

func New

func New(ctx context.Context, input Config) (*Pool, error)

New constructs a native pgxpool and, by default, proves connectivity with a bounded ping. StartupLazy skips that initial network operation.

func (*Pool) Acquire

func (p *Pool) Acquire(ctx context.Context) (*pgxpool.Conn, error)

Acquire obtains a connection while honoring the earlier of the caller's deadline and the configured acquisition timeout.

func (*Pool) Close

func (p *Pool) Close(ctx context.Context) error

Close begins native pool shutdown exactly once and waits only until the earlier of the caller deadline or configured shutdown timeout. A timed-out close continues in the background until borrowed connections are returned.

func (*Pool) Liveness

func (p *Pool) Liveness() Health

Liveness reports whether pool shutdown has started without contacting the database. Database availability belongs to Readiness rather than liveness.

func (*Pool) Ping

func (p *Pool) Ping(ctx context.Context) error

Ping checks PostgreSQL connectivity with a strict configured deadline.

func (*Pool) Raw

func (p *Pool) Raw() *pgxpool.Pool

Raw returns the underlying pgxpool without wrapping or copying it.

func (*Pool) Readiness

func (p *Pool) Readiness(ctx context.Context) Health

Readiness performs a bounded ping and returns a pool-statistics snapshot.

func (*Pool) Stats

func (p *Pool) Stats() Stats

Stats returns an immutable copy of the native pgxpool counters and gauges.

type PoolConfig

type PoolConfig = pgxpool.Config

PoolConfig is the native pgxpool configuration type. The alias makes hooks explicit while preserving direct access to every pgxpool option.

func ParseConfig

func ParseConfig(input Config) (*PoolConfig, error)

ParseConfig parses the DSN, applies finite defaults and overrides, validates pool invariants, and finally invokes Config.Configure.

type SavepointOptions

type SavepointOptions struct {
	CleanupTimeout time.Duration
	Observer       Observer
}

SavepointOptions controls cleanup and observation for a nested transaction.

type StartupPolicy

type StartupPolicy uint8

StartupPolicy controls whether New proves connectivity before returning.

const (
	// StartupPing is the fail-fast default and pings PostgreSQL during New.
	StartupPing StartupPolicy = iota
	// StartupLazy returns after pool construction without opening a connection.
	StartupLazy
)

type Stats

type Stats struct {
	AcquireCount         int64
	AcquiredConns        int32
	CanceledAcquireCount int64
	ConstructingConns    int32
	EmptyAcquireCount    int64
	EmptyAcquireWaitTime time.Duration
	IdleConns            int32
	MaxConns             int32
	NewConnsCount        int64
	TotalConns           int32
}

Stats is an immutable snapshot of native pgxpool statistics.

type TLSConfig

type TLSConfig struct {
	Mode   TLSMode
	Config *tls.Config
}

TLSConfig is an explicit TLS override. TLSRequire clones Config before use, so callers cannot mutate live connection settings through the input pointer.

type TLSMode

type TLSMode uint8

TLSMode controls whether typed TLS settings override the DSN.

const (
	// TLSFromDSN preserves pgx parsing of sslmode and related DSN settings.
	TLSFromDSN TLSMode = iota
	// TLSDisable explicitly disables TLS for every configured host.
	TLSDisable
	// TLSRequire requires the supplied tls.Config for every configured host.
	TLSRequire
)

type TransactionOptions

type TransactionOptions struct {
	pgx.TxOptions
	CleanupTimeout time.Duration
	Observer       Observer
}

TransactionOptions combines native pgx transaction modes with the bounded cleanup policy used when the callback returns an error or panics.

Directories

Path Synopsis
examples
service command
sqlc command
worker command
Package otelpostgres adapts go-postgres observations to standard OpenTelemetry metrics without recording SQL, arguments, DSNs, or raw errors.
Package otelpostgres adapts go-postgres observations to standard OpenTelemetry metrics without recording SQL, arguments, DSNs, or raw errors.
Package postgrestest provides real PostgreSQL containers for integration tests.
Package postgrestest provides real PostgreSQL containers for integration tests.

Jump to

Keyboard shortcuts

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