ubgo is in early alpha: libraries and APIs may still change.

Skip to content
ubgo Alpha

lock

One lock interface with five backends (filelock, flock, Redis, Postgres, etcd) and fencing tokens.

go get github.com/ubgo/lock
Language
Go
Go version
1.24
Core deps
0 direct
Latest tag
v0.1.0
License
Apache-2.0
Go modules
8

How it fits together

Highlights from the README

  • One contract. All five backends satisfy lock.Locker. Your service code accepts lock.Locker and you swap concrete factories at startup. flock for local dev → pglock in staging → etcdlock in prod, with zero application-code changes.
  • Production-grade defaults. Crash recovery, fencing tokens, observability hooks, structured logging, periodic stale cleanup. Things every “tutorial” lock library forgets.
  • No-surprise semantics. Every backend’s Acquire is non-blocking and returns lock.ErrLocked on contention — same sentinel everywhere. No backend silently waits, no backend uses a custom error type. Predictable.
  • Tested across platforms. Linux, macOS, Windows in CI. Real Postgres + real etcd in CI service containers. Unit tests run in milliseconds via memlock.
  • Minimal cores. The interface module has zero deps. Each backend has only the deps it needs (e.g. pglock has pgx, redislock has go-redis — never both).

Code from the README

package payments

import (
    "context"
    "errors"

    "github.com/ubgo/lock"
)

type Service struct {
    locks lock.Locker
}

func (s *Service) DailyExport(ctx context.Context) error {
    h, err := s.locks.Acquire(ctx, "daily-export")
    if errors.Is(err, lock.ErrLocked) {
        return nil // another worker is on it; skip
    }
    if err != nil {
        return err
    }
    defer h.Release()

    return s.runExport(ctx)
}

From the lock README.

At a glance (from the README)

Concernfilelockflockredislockpglocketcdlock
Scopesingle-hostsingle-hostmulti-hostmulti-hostmulti-host
Crash recoveryPID probe + stale window + SweepKernel — instant on fd closeTTL expirySession closeLease expiry
Need extra infranonenoneRedisPostgresetcd cluster
TTL to tuneoptionalnoneyesnoneyes
Reentrantnononoyes (PG native)no
Fencing tokensper-name sidecarper-name sidecarper-name INCRper-session txidmod_revision (global)
Semaphore (WithMaxConcurrent)✅✅✅✅✅
Sweep✅n/a (kernel cleans)n/a (TTL cleans)n/a (session cleans)n/a (lease cleans)
Operator visibilityrich marker fieldsnoneredis-cli GET <key>pg_locks viewetcdctl get <key>
Observability hooks✅ slog/metrics/spans✅ same✅ same✅ same✅ same
TraceID propagationmarker debug fieldslog fieldembedded in SET valuevia application_namein lock key value
Strong consistencylocal-fs onlylocal-fs onlyweakly (AP)ACID single primary✅ Raft