Distributed locking primitives for Redis. Mutex for exclusive locks, semaphore for N concurrent leases. All operations are atomic via Lua scripts, and locks auto-expire on crash via TTL.
npm install @prsm/lockExclusive lock. One holder at a time.
import{mutex}from"@prsm/lock"constlock=mutex({redis: {host: "127.0.0.1",port: 6379},})const{ acquired, id }=awaitlock.acquire("my-job",{ttl: "30s"})if(!acquired)returntry{awaitdoWork()}finally{awaitlock.release("my-job",id)}redis-{ url?, host?, port?, password? }passed to node-redisprefix- Redis key prefix (default"lock:mutex:")
| Method | Returns | Description |
|---|---|---|
acquire(key, opts?) | { acquired, id } | Attempt to acquire. opts.ttl (default "10s"), opts.id (custom holder ID) |
release(key, id) | boolean | Release only if you still own it |
peek(key) | { held, holder, ttl } | Check lock state without acquiring |
close() | void | Disconnect Redis |
Up to N concurrent holders.
import{semaphore}from"@prsm/lock"constsem=semaphore({max: 20,ttl: "60s",redis: {host: "127.0.0.1",port: 6379},})const{ acquired, id }=awaitsem.acquire("worker-slots")if(!acquired)returnconstheartbeat=setInterval(()=>sem.renew("worker-slots",id),15000)try{awaitprocessTask()}finally{clearInterval(heartbeat)awaitsem.release("worker-slots",id)}max- Maximum concurrent holders (required)ttl- Lease lifetime (default"60s"). Expired leases are pruned automaticallyredis- Same as mutexprefix- Redis key prefix (default"lock:sem:")
| Method | Returns | Description |
|---|---|---|
acquire(key, opts?) | { acquired, id } | Acquire a lease slot. opts.id for custom lease ID |
release(key, id) | true | Release a lease |
renew(key, id) | boolean | Extend lease lifetime. false if expired |
count(key) | number | Active lease count (after pruning) |
peek(key) | { active, max, available, holders } | Full semaphore state |
close() | void | Disconnect Redis |
Mutex uses SET key value NX PX ttl for atomic acquire and a Lua script for ownership-checked release (only the holder can release).
Semaphore uses a Redis sorted set where each member is a lease ID and the score is a timestamp. Expired entries are pruned via ZREMRANGEBYSCORE before each acquire. Renewal updates the timestamp to extend the lease window.
Both are crash-tolerant via TTLs. If a holder dies without releasing, the lock/lease expires automatically.