Skip to content

academia-edu/redis_locks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Redis Locks

Various locking utilities for Ruby using Redis.

All classes are designed to work with Ruby clients distributed across multiple processes and/or machines, but assume a single Redis master for correctness.

Works with Redis 2.6+.

Utilities

RedisLocks::Mutex

A simple mutex using setnx.

  require 'redis'
  require 'redis_locks'

  RedisLocks.redis = Redis.new

  lock = RedisLocks::Mutex.new('my_key')

  # high-level use
  lock.lock! do 
    # something that can only be done by one process at a time
  end

  # lower-level options
  lock.lock # acquires lock & returns true
  lock.lock # returns false, lock was not acquired
  lock.unlock # now lock can be acquired again

Supports lock expiry via an expires_in argument to the constructor or expires_at argument to lock/lock!. By default, locks expire after 24 hours.

RedisLocks::Semaphore

A semaphore implemented with Lua and lpop/blpop.

Supports multiple resources, waits to acquire a resource, and timeouts.

  require 'redis'
  require 'redis_locks'

  RedisLocks.redis = Redis.new

  semaphore = RedisLocks::Semaphore.new('my_key', resources: 2)

  # high-level use
  semaphore.lock! do
    # something that can be done by at most two processes at a time
  end

  # will wait indefinitely for a resource to be free, if necessary (this
  # counter-intuitive use of zero values reflects that of Redis' `blpop`)
  semaphore.lock!(timeout: 0) { }

  # will wait up to 1 second for a resource to be free
  semaphore.lock!(timeout: 1) { }

  # lower-level options
  semaphore.lock # acquires resource & returns true
  semaphore.lock # acquires another resource & returns true
  semaphore.lock # returns false, no resources remain
  semaphore.unlock # frees a resource

Supports expiry via stale_client_timeout argument to the constructor. By default, clients are timed out after 24 hours.

RedisLocks::TokenBucket

A token-bucket rate limiter implemented with Lua.

  require 'redis'
  require 'redis_locks'

  RedisLocks.redis = Redis.new

  # allows up to two calls to `take`/`take!` every five seconds
  limiter = RedisLocks::TokenBucket.new('my_key', period: 5, number: 2)

  2.times { limiter.take! }

  limiter.take # false if zero microseconds have passed, true otherwise (in which case a new token has become available)
  limiter.take! # raises RateLimitExceeded

  sleep(5)

  limiter.take # true

Configuration

We use a connection pool, because a connection shared among multiple threads will result in contention when using blocking Redis operations.

RedisLocks.redis= and the redis: option in the initializer for each utility can each be passed either a plain Redis object or an object responding to with (which will be expected to accept a block and yield a Redis connection, e.g. an instance of ConnectionPool).

About

Locking utilities for Ruby using Redis

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages