module Redis::Lock

Constants

VERSION

Public Instance Methods

lock(key, timeout = 60, max_attempts = 100) click to toggle source

Lock a given key. Optionally takes a timeout and max number of attempts to lock the key before giving up.

Example:

$redis.lock('beers_on_the_wall', 10, 100)

# File lib/redis/lock.rb, line 33
def lock(key, timeout = 60, max_attempts = 100)
  current_lock_key = lock_key(key)
  expiration_value = lock_expiration(timeout)
  attempt_counter = 0
  while attempt_counter < max_attempts
    if self.setnx(current_lock_key, expiration_value)
      return true
    else
      current_lock = self.get(current_lock_key)
      if (current_lock.to_s.split('-').first.to_i) < Time.now.to_i
        compare_value = self.getset(current_lock_key, expiration_value)
        return true if compare_value == current_lock
      end
    end

    attempt_counter += 1
    sleep 1 if attempt_counter < max_attempts
  end

  raise RedisLockException.new("Unable to acquire lock for #{key}.")
end
lock_for_update(key, timeout = 60, max_attempts = 100) { || ... } click to toggle source

Lock a given key for updating

Example:

$redis = Redis.new lock_for_update('beers_on_the_wall', 20, 1000) do

$redis.decr('beers_on_the_wall')

end

# File lib/redis/lock.rb, line 15
def lock_for_update(key, timeout = 60, max_attempts = 100)
  if self.lock(key, timeout, max_attempts)
    response = nil
    begin
      response = yield if block_given?
    ensure
      self.unlock(key)
    end
    return response
  end
end
unlock(key) click to toggle source

Unlock a previously locked key if it has not expired and the current process/thread was the one that locked it.

Example:

$redis.unlock('beers_on_the_wall')

# File lib/redis/lock.rb, line 61
def unlock(key)
  current_lock_key = lock_key(key)
  lock_value = self.get(current_lock_key)
  return true unless lock_value
  lock_timeout, lock_process, lock_thread = lock_value.split('-')
  if (lock_timeout.to_i > Time.now.to_i) && (lock_process.to_i == Process.pid) && lock_thread.to_i == Thread.current.object_id
    self.del(current_lock_key)
    return true
  else
    return false
  end
end

Private Instance Methods

lock_expiration(timeout) click to toggle source
# File lib/redis/lock.rb, line 76
def lock_expiration(timeout)
  "#{Time.now.to_i + timeout + 1}-#{Process.pid}-#{Thread.current.object_id}"
end
lock_key(key) click to toggle source
# File lib/redis/lock.rb, line 80
def lock_key(key)
  "lock:#{key}"
end