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

lock

package
v0.0.13 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package lock is a pluggable distributed-lock contract. Used by consumer apps to serialise work across replicas — typically concurrent=false scheduled jobs that may fire on more than one pod.

Every backend takes a required TTL on Acquire — the lock self- expires after the deadline so a crashed holder doesn't permanently poison the key. Pick a TTL longer than your expected critical section plus headroom; the lock can be released early via Handle.Release.

Backends

  • NoOp — every Acquire succeeds.
  • Memory — process-local mutex.
  • lock/postgreslock — table-based, opt-in import (uses pgxpool).
  • lock/redislock — SET NX PX + Lua release, opt-in import (uses github.com/redis/go-redis/v9).

Example

lp := lock.NewMemory()
h, err := lp.Acquire(ctx, "orders:dispatch", 30*time.Second)
if err != nil { return err }
if h == nil { return nil } // contended; skip this firing
defer h.Release(ctx)
// critical section …

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidTTL — TTL was zero or negative.
	ErrInvalidTTL = errors.New("lock: TTL must be greater than zero")
	// ErrBackend — backend-level I/O failure.
	ErrBackend = errors.New("lock: backend error")
)

Sentinel errors. Use errors.Is to branch.

Functions

func BackendErr

func BackendErr(format string, a ...any) error

BackendErr wraps a driver error as ErrBackend so callers can use errors.Is(err, lock.ErrBackend).

func EnsurePositiveTTL

func EnsurePositiveTTL(ttl time.Duration) error

EnsurePositiveTTL is the standard guard at the trait boundary so every backend returns the same error shape.

Types

type Handle

type Handle interface {
	// Release frees the lock. Idempotent — safe to call multiple
	// times, though only the first call does work.
	Release(ctx context.Context) error
}

Handle is returned by a successful Acquire. Always call Release when the critical section is done; Go has no Drop, so leaving Release uncalled relies entirely on TTL expiry to free the key.

type Memory

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

Memory is a process-local lock provider. Serialises holders for a given key inside this process. Does NOT survive multiple replicas — use postgreslock or redislock for that.

func NewMemory

func NewMemory() *Memory

NewMemory builds an empty Memory provider.

func (*Memory) Acquire

func (m *Memory) Acquire(_ context.Context, key string, ttl time.Duration) (Handle, error)

Acquire — see Provider.Acquire.

type NoOp

type NoOp struct{}

NoOp is a lock provider whose Acquire always succeeds. Use when the underlying work can run concurrently or when you de-dupe by some other means (idempotency keys, partition assignment, etc.).

func NewNoOp

func NewNoOp() *NoOp

NewNoOp builds a NoOp provider.

func (*NoOp) Acquire

func (*NoOp) Acquire(_ context.Context, _ string, _ time.Duration) (Handle, error)

Acquire always returns a no-op handle.

type Provider

type Provider interface {
	Acquire(ctx context.Context, key string, ttl time.Duration) (Handle, error)
}

Provider is the pluggable distributed-lock contract.

Acquire is non-blocking: it returns (nil, nil) immediately when the key is held by another holder. The caller decides whether to retry, skip, or fail. ttl bounds how long a crashed holder can keep the lock for.

Directories

Path Synopsis
Package postgreslock is a table-based distributed lock that satisfies lock.Provider.
Package postgreslock is a table-based distributed lock that satisfies lock.Provider.
Package redislock is a Redis-backed distributed lock that satisfies lock.Provider.
Package redislock is a Redis-backed distributed lock that satisfies lock.Provider.

Jump to

Keyboard shortcuts

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