Redis Distributed Locks Explained
· 1 min read
A distributed lock is just a key that only one process can create. In Redis
that’s SET key value NX PX ttl — NX makes it fail if the key exists, PX
gives it a deadline so a crashed holder can’t keep the lock forever.
ok, err := rdb.SetNX(ctx, "lock:invoices", token, 30*time.Second).Result()
if err != nil || !ok {
return ErrLocked
}
defer release(ctx, rdb, "lock:invoices", token)
The part people get wrong
Releasing with a plain DEL is a bug. If your work ran past the TTL, the lock
already expired and someone else holds it — your DEL deletes their lock.
Store a random token as the value and delete only if it still matches, which
has to be atomic:
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
end
return 0
Rules of thumb
- TTL should be longer than the worst-case run time, not the average.
- If the work can outlive the TTL, you need a watchdog that extends it.
- A single-node Redis lock is best-effort. If correctness genuinely depends on mutual exclusion, put the guarantee in the database instead.