Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrLockAlreadyAcquired = errors.New("lock already acquired")
ErrLockAlreadyAcquired is returned by AcquireLock when called on a *Postgres that already holds the advisory lock.
var ErrLockNotAcquired = errors.New("lock not acquired")
ErrLockNotAcquired is returned by ReleaseLock when called on a *Postgres that does not currently hold the advisory lock.
var ErrLockNotHeld = errors.New("advisory lock was not held at release time")
ErrLockNotHeld is returned by ReleaseLock when pg_advisory_unlock reports the lock was not held by this session, meaning something released it out of band.
var ErrLockTimeout = errors.New("timed out waiting for the migration advisory lock")
ErrLockTimeout is returned by AcquireLock when the configured lock timeout elapsed while waiting, which means another process holds the migration lock. Postgres aborts the waiting statement itself, so this reliably means the lock was not granted.
var ErrPoolTooSmall = errors.New(
"sql.DB allows only 1 open connection: the advisory lock pins a dedicated " +
"connection for the whole migration run, so at least 2 concurrent connections " +
"are required (call SetMaxOpenConns(0) or >= 2)",
)
ErrPoolTooSmall is returned by AcquireLock when the underlying *sql.DB is configured with SetMaxOpenConns(1). The advisory lock pins a dedicated connection for the whole migration run, so at least 2 concurrent connections are required or every other query would block forever waiting for a connection that can never free up.
Functions ¶
This section is empty.
Types ¶
type Postgres ¶
type Postgres struct {
// contains filtered or unexported fields
}
func NewPostgresFromDB ¶
func NewPostgresFromDB(db *sql.DB, cfg PostgresConfig) *Postgres
NewPostgresFromDB wraps an already-open *sql.DB (opened by the caller with whatever driver they choose) in a *Postgres. See internal/dbconn for a pgx-backed constructor that opens the connection itself.
func (*Postgres) AcquireLock ¶
AcquireLock acquires the advisory lock on a dedicated connection, waiting at most the configured lock timeout.
The timeout is enforced by the server via lock_timeout rather than by cancelling the query from the client. That distinction matters: a cancelled query may already have been granted the lock, and since the connection then goes back to the pool rather than being closed, the lock would be stranded on a pooled connection with nothing tracking it. A server-side abort is unambiguous — the lock was not granted.
lock_timeout is set with transaction scope, so it reverts on COMMIT and never leaks onto the pooled connection. The advisory lock is session-scoped and outlives that transaction.
func (*Postgres) ExportLockConn ¶
ExportLockConn exposes the private lockConn field for testing.
func (*Postgres) ReleaseLock ¶
ReleaseLock releases the advisory lock and returns the dedicated connection to the pool.
The release is not optional. (*sql.Conn).Close only returns the connection to the pool — the session stays alive, so a session-level advisory lock survives it. If the lock cannot be confirmed released, the connection is destroyed rather than reused, since Postgres does release the lock when the session actually ends.
type PostgresConfig ¶
type PostgresConfig struct {
// DSN, when set, is used verbatim and every discrete field below is ignored.
// Both the URL form ("postgres://user:pass@host/db?sslmode=require") and the
// keyword/value form ("host=... dbname=...") are accepted, since pgx parses
// either.
DSN string
Host string
Port string
User string
Password string
DBName string
// SSLMode maps to libpq's sslmode. Empty leaves it unset, so the driver's
// own default applies ("prefer": TLS when the server offers it, plaintext
// otherwise). Managed Postgres generally needs "require" or stricter.
SSLMode string
// LockTimeout bounds the wait for the advisory lock. Zero is ambiguous on its
// own, so LockTimeoutSet says whether it was configured: unset means the
// default, an explicit zero means wait indefinitely (Postgres' lock_timeout=0).
LockTimeout time.Duration
LockTimeoutSet bool
LockID int64
}
func (PostgresConfig) GetDataSource ¶
func (c PostgresConfig) GetDataSource() string
GetDataSource returns the connection string.
A DSN set explicitly is returned as-is. Otherwise a keyword/value string is built from the discrete fields, quoting values per libpq's rules: a value is wrapped in single quotes (with internal \ and ' backslash-escaped) when it contains whitespace, a single quote or a backslash.
Empty fields are omitted rather than emitted as empty values, so that the driver's defaults and the standard PG* environment variables still apply to anything not configured here. Emitting them bare would be unsafe in any case: libpq's parser swallows the next key=value pair as the value of an empty key.