postgres

package
v9.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 2, 2026 License: AGPL-3.0 Imports: 21 Imported by: 0

Documentation

Overview

Package postgres implements distributedlock.Locker against PostgreSQL session- scoped advisory locks (pg_try_advisory_lock). It uses an existing platform/database.Client for connection management.

TTL semantics: PostgreSQL advisory locks have no native TTL, so this provider enforces the TTL client-side. Acquire stamps an expiry, Expired reports against it, and Refresh both verifies the underlying session is alive and extends the expiry by the TTL it is given.

What that does and does not buy you is worth being precise about. The expiry is this process's own bookkeeping: it stops a caller from believing it still holds a lock it has held past its TTL. It is not enforced by the database, so a process that ignores Expired keeps the advisory lock until Release is called or the dedicated session ends (a network failure, or Locker.Close). Another process will not acquire the lock merely because the first one's TTL lapsed — for a hard, server-side bound, use a lease table rather than advisory locks.

Each Acquire reserves a dedicated *sql.Conn from the database client's pool so that the matching pg_advisory_unlock targets the same session. The Locker tracks outstanding connections internally and releases all of them on Close.

Index

Constants

View Source
const DefaultConnWaitTimeout = 5 * time.Second

DefaultConnWaitTimeout bounds how long Acquire waits to reserve a write-pool connection before giving up. See Config.ConnWaitTimeout.

Variables

This section is empty.

Functions

func NewPostgresLocker

func NewPostgresLocker(
	cfg *Config,
	db database.Client,
	cb circuitbreaking.CircuitBreaker,
	opts ...Option,
) (distributedlock.Locker, error)

NewPostgresLocker constructs a new postgres-backed distributedlock.Locker.

func NewPostgresScopedLocker

func NewPostgresScopedLocker(
	cfg *Config,
	db database.Client,
	cb circuitbreaking.CircuitBreaker,
	opts ...Option,
) (distributedlock.ScopedLocker, error)

NewPostgresScopedLocker constructs a transaction-scoped distributedlock.ScopedLocker. Unlike NewPostgresLocker it needs only the safe database.Client surface (WithTransaction), not RawAccess.

fn runs while the calling transaction holds the advisory lock, but receives only a context: any database work fn performs goes through its own connections and is NOT part of the lock-holding transaction. WithLock waits in the database (pg_advisory_xact_lock queues server-side, so waiters need no polling and are granted the lock in request order); each in-flight call occupies one write-pool connection for fn's duration.

Types

type Config

type Config struct {
	// Namespace is mixed into the lock-id hash so independent services sharing a
	// Postgres cluster do not collide on the same advisory-lock id space.
	Namespace int32 `env:"NAMESPACE" envDefault:"0" json:"namespace" yaml:"namespace"`

	// ConnWaitTimeout bounds how long Acquire will wait to reserve a connection
	// from the write pool. Each held lock pins one write connection for its whole
	// lifetime, so a saturated pool would otherwise make Acquire block indefinitely
	// in database/sql's Conn(). When the wait is exceeded, Acquire returns
	// distributedlock.ErrLockNotAcquired instead of blocking. Zero uses
	// DefaultConnWaitTimeout; a negative value disables the bound (wait forever).
	ConnWaitTimeout time.Duration `env:"CONN_WAIT_TIMEOUT" envDefault:"5s" json:"connWaitTimeout" yaml:"connWaitTimeout"`
}

Config configures a Postgres-backed distributed locker. Namespace is mixed into the lock-id hash so independent services that share a Postgres cluster do not collide on the same advisory-lock id space.

func (*Config) ValidateWithContext

func (cfg *Config) ValidateWithContext(_ context.Context) error

ValidateWithContext validates a Config struct. Namespace has no upper bound; any int32 is acceptable.

type Option

type Option func(*options)

Option configures the postgres-backed lockers this package constructs. The zero configuration works: an absent logger logs nowhere, an absent tracer provider traces nowhere, and an absent metrics provider records nothing.

func WithLogger

func WithLogger(logger logging.Logger) Option

WithLogger attaches a logger.

func WithMetricsProvider

func WithMetricsProvider(metricsProvider metrics.Provider) Option

WithMetricsProvider attaches a metrics provider for the locker's counters and latency histogram.

func WithTracerProvider

func WithTracerProvider(tracerProvider tracing.TracerProvider) Option

WithTracerProvider attaches a tracer provider, enabling spans on every lock operation.

Jump to

Keyboard shortcuts

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