lock

package
v0.8.1 Latest Latest
Warning

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

Go to latest
Published: Jul 20, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package lock provides distributed mutual exclusion for work that must run on at most one replica at a time — most commonly a scheduled job (see the cron package and `skit add cron`). A Locker hands out a short-lived, best-effort lock keyed by a name; the holder does the work and releases it.

Two backends implement Locker:

  • PG (Postgres advisory locks): pg_try_advisory_lock on a dedicated connection. No external infrastructure beyond the database you already have; the lock releases automatically if the holding connection dies.
  • Redis (SET NX PX + a token-checked release): a TTL bounds how long a crashed holder can block others; release is fenced by a random token so one holder never frees another's lock.

The contract is deliberately minimal and non-blocking: TryLock either grabs the lock now or reports it is held elsewhere. Callers that miss the lock skip this round rather than queue — the right behavior for periodic jobs.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Locker

type Locker interface {
	// TryLock attempts to acquire the lock named key without blocking. On
	// success it returns ok==true and a Release to free the lock. If another
	// holder has it, ok==false and Release is a no-op. err is non-nil only on an
	// infrastructure failure (the caller cannot tell whether the lock is free).
	//
	// ttl bounds how long the lock survives a crashed holder: the Redis backend
	// expires the key after ttl, while the Postgres backend ignores ttl and
	// relies on connection death (its lock is session-scoped). Hold the lock only
	// for the duration of the guarded work, then Release.
	TryLock(ctx context.Context, key string, ttl time.Duration) (Release, bool, error)
}

Locker grants best-effort, single-holder locks.

type PG

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

PG is a Locker backed by Postgres session-scoped advisory locks (pg_try_advisory_lock). Each TryLock checks out a dedicated connection and holds the lock on it; Release unlocks and returns the connection. If the holder crashes, Postgres drops the connection and releases the lock automatically, so a lock can never leak — this is why PG ignores ttl.

func NewPG

func NewPG(db *sqlx.DB, log *slog.Logger) *PG

NewPG builds a Postgres advisory-lock Locker over db. log may be nil.

func (*PG) TryLock

func (p *PG) TryLock(ctx context.Context, key string, _ time.Duration) (Release, bool, error)

TryLock acquires pg_try_advisory_lock(key-hash) on a dedicated connection. ttl is ignored (the lock is session-scoped and released on Release or connection death). ok==false means another session holds the lock.

type Redis

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

Redis is a Locker backed by Redis. It acquires with SET key token NX PX ttl (atomic "set if absent with expiry") and releases with a Lua script that deletes the key only if it still holds this holder's token. The token fence stops one holder from freeing a lock that already expired and was retaken by another — the classic Redlock single-instance release.

func NewRedis

func NewRedis(client redis.Cmdable, log *slog.Logger) *Redis

NewRedis builds a Redis Locker over client (a *redis.Client or *redis.ClusterClient). log may be nil.

func (*Redis) TryLock

func (r *Redis) TryLock(ctx context.Context, key string, ttl time.Duration) (Release, bool, error)

TryLock runs SET key token NX PX ttl. ok==false means the key already exists (another holder). ttl must be > 0; it bounds how long a crashed holder blocks others.

type Release

type Release func()

Release frees a held lock. It is safe to call exactly once; implementations make a best effort and never panic. A Release returned with ok==false from TryLock is a no-op.

Jump to

Keyboard shortcuts

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