npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

redis-exp-lock

v0.0.2

Published

Distributed lock using Redis and Lua

Downloads

34

Readme

redis-exp-lock-js

Uses Redis to provide a mechanism for distributed mutual exclusion. If you want to prevent multiple nodes on a network from accessing a resource at the same time, this is for you. This lock implementation uses a finite but configurable expiration time.

Unlike most SETNX-based solutions, this uses Redis's Lua functionality. The result is cleaner code and fewer race conditions. Lock expiration is handled by the Redis server itself, using the EXPIRE command, thus eliminating the need for precise time synchronization between your application hosts.

Example

redis = require('redis');
redisExpLock = require('redis-exp-lock');

// Configure a lock function
withLock = redisExpLock({redis: redis.createClient()});

// Use the lock function to provide mutual exclusion.
withLock(function(err, critSecDone) {
  if (err) throw err;
  doStuffThatShouldNotBeInterrupted();
  critSecDone();
});

How to use the library

Installation

npm install redis-exp-lock

Setup

Requiring the module will result in a lock configuration function.

redisExpLock = require('redis-exp-lock')

Calling the lock configuration function yields a lock function that will peform the actual locking. The lock configuration function takes one optional configuration argument, an object with any of the following fields:

redis

The Redis client.

lifetime

The lifetime of the lock, in milliseconds. A lock's lifetime begins counting down as soon as the Redis server receives an EXPIRE command from the lock function. Defaults to 1000 milliseconds (one second).

maxRetries

In the event that the lock has been acquired by another process, the lock function can automatically attempt to re-acquire the lock, up to a configurable number of attempts. Defaults to zero (no automatic retries).

retryTimeout

The amount of time the lock function will wait before attempting to re-acquire the lock. Defaults to five milliseconds.

Acquiring and releasing the lock

The lock function takes two or three arguments:

  • A Redis key where the lock will be stored. This is most likely the name of the resource you are trying to lock.
  • An optional settings object, with overrides to the original lock configuration.
  • A callback that takes two arguments:
    • An error object. This is null if the lock attempt was successful.
    • A release function, to be called in your application code after the critical section has completed. This will cause the lock to be released. Since the release function is itself asynchronous, you can pass it a callback that will be invoked when the release has been confirmed.
withLock = redisExpLock({redis: redis.createClient(), maxRetries: 2});

withLock('bankAccount', function(err, critSecDone) {
  if (err) return;
  bankAccount.addMoney(100000);

  critSecDone(function(err) {
    if (err) return;
    console.log("Lock successfully released!");
  });
});

Algorithm

Lock acquisition

Locks are acquired by setting a Redis key with a UUID generated immediately prior to the lock attempt. A Lua script provides the following atomic sequence:

  1. Use SETNX to set the value of the given key to the UUID.
  2. If SETNX was successful, use PEXPIRE to set a lifetime on the key, managed by Redis.

Since the Redis server manages the lifetime, there is no need for any client-side logic for managing lock expiration, and thus no need to ensure that clients are time-synchronized.

Lock release

Locks are released by deleting the Redis key, if and only if the key's value matches the UUID generated during a successful lock attempt. A Lua script provides the following atomic sequence:

  1. GET the value of the key.
  2. If the value of the key is the same as the UUID, then use DEL to remove the key.

Without using a Lua script to ensure atomicity, it's possible to encounter subtle race conditions, in which another client acquires the lock between the two steps above.