Distributed Lock
Warp provides a distributed locking primitive with multiple backends.
API Reference
NewInMemory
func NewInMemory(bus syncbus.Bus) *InMemory
Creates a new in-memory locker that uses the provided bus for coordination.
NewRedis
func NewRedis(client redis.UniversalClient) *Redis
Creates a new Redis-backed locker using SET NX EX for atomic acquisition and
a Lua ownership-check script for safe release. client may be a standalone,
Sentinel, or cluster client (redis.UniversalClient).
Acquire strategy
Acquire subscribes to __keyevent@0__:del and __keyevent@0__:expired for
prompt wake-up when the lock is freed. If keyspace notifications are disabled
on the server it falls back automatically to exponential-backoff polling
(5 ms → 500 ms). Enable notifications with notify-keyspace-events "KEx" for
best latency.
Ownership guarantee
Each TryLock generates a unique UUID token stored as the Redis key’s value.
Release runs a Lua script that deletes the key only when the stored value
matches the caller’s token — preventing any other holder from being evicted.
NewNATS
func NewNATS(js jetstream.JetStream, bucket string) *NATS
Creates a new NATS JetStream-backed distributed locker. bucket is the JetStream
KV bucket name; it is created automatically if absent. No Redis required.
nc, _ := nats.Connect(nats.DefaultURL)
js, _ := jetstream.New(nc)
locker := lock.NewNATS(js, "my-locks")
Locker Interface
type Locker interface {
Acquire(ctx context.Context, key string, ttl time.Duration) error
TryLock(ctx context.Context, key string, ttl time.Duration) (bool, error)
Release(ctx context.Context, key string) error
}
Acquire
func (l *Locker) Acquire(ctx context.Context, key string, ttl time.Duration) error
Attempts to acquire the lock. Blocks until acquired or context expires.
- key: Resource identifier.
- ttl: Safety timeout. If the holder crashes, the lock is auto-released after this duration.
TryLock
func (l *Locker) TryLock(ctx context.Context, key string, ttl time.Duration) (bool, error)
Non-blocking attempt. Returns true if acquired immediately, false otherwise.
Release
func (l *Locker) Release(ctx context.Context, key string) error
Releases the lock and notifies waiting nodes.
Use Cases
1. Leader Election
Ensure only one node performs a scheduled task.
2. Resource Exclusive Access
Prevent race conditions when modifying a shared external resource.