A Redis Locker that can be used as both:

  • a Read Write Locker that uses a (single) Redis server to store the locks and counts.
  • a Resource Locker that uses a (single) Redis server to store the lock. This solution should be process-safe. The only references to locks are string keys derived from identifier paths.

The Read Write algorithm roughly goes as follows:

  • Acquire a read lock: allowed as long as there is no write lock. On acquiring the read counter goes up.
  • Acquire a write lock: allowed as long as there is no other write lock AND the read counter is 0.
  • Release a read lock: decreases the read counter with 1
  • Release a write lock: unlocks the write lock

The Resource locking algorithm uses a single mutex/lock.

All operations, such as checking for a write lock AND read count, are executed in a single Lua script. These scripts are used by Redis as a single new command. Redis executes its operations in a single thread, as such, each such operation can be considered atomic.

See

Hierarchy

  • RedisLocker

Implements

Constructors

Properties

attemptSettings: Required<AttemptSettings>
logger: Logger = ...
redis: Redis
redisLock: RedisResourceLock
redisRw: RedisReadWriteLock

Methods

  • Generate and return a RedisClient based on the provided string

    Parameters

    • redisClientString: string

      A string that contains either a host address and a port number like '127.0.0.1:6379' or just a port number like '6379'.

    Returns Redis

  • Releases a lock on the requested identifier. The promise will resolve when the lock has been released. In case there is no lock on the resource an error should be thrown.

    Parameters

    Returns Promise<void>

  • Try a Redis function according to the set AttemptSettings Since the locking strategy is custom-built on Redis and Redis itself does not have a lock concept, this function allows us to wait until we acquired a lock.

    The AttemptSettings will dictate how many times we should retry the Redis functions before giving up and throwing an error.

    Returns

    Promise that resolves if operation succeeded. Rejects with error otherwise

    See

    To convert from Redis operation to Promise use fromResp2ToBool to wrap the function

    Parameters

    • fn: (() => Promise<boolean>)

      The function to try

        • (): Promise<boolean>
        • Returns Promise<boolean>

    Returns Promise<void>

  • Run the given function while the resource is locked. The lock will be released when the (async) input function resolves. This function should be used for operations that only require reading the resource.

    Returns

    A promise resolving when the lock is released.

    Type Parameters

    • T

    Parameters

    • identifier: ResourceIdentifier

      Identifier of the resource that needs to be locked.

    • whileLocked: (() => T | Promise<T>)

      A function to execute while the resource is locked.

        • (): T | Promise<T>
        • Returns T | Promise<T>

    Returns Promise<T>

  • Run the given function while the resource is locked. The lock will be released when the (async) input function resolves. This function should be used for operations that could modify the resource.

    Returns

    A promise resolving when the lock is released.

    Type Parameters

    • T

    Parameters

    • identifier: ResourceIdentifier

      Identifier of the resource that needs to be locked.

    • whileLocked: (() => T | Promise<T>)

      A function to execute while the resource is locked.

        • (): T | Promise<T>
        • Returns T | Promise<T>

    Returns Promise<T>