Module: Redis::Lock

Included in:
Redis
Defined in:
lib/redis/lock.rb

Instance Method Summary collapse

Instance Method Details

#lock(key, timeout = 60, max_attempts = 100) ⇒ Object

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)



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/redis/lock.rb', line 29

def lock(key, timeout = 60, max_attempts = 100)
  current_lock_key = lock_key(key)
  expiration_value = lock_expiration(timeout)
  attempt_counter = 0
  begin
    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
  
    raise "Unable to acquire lock for #{key}."
  rescue => e
    if e.message == "Unable to acquire lock for #{key}."
      if attempt_counter == max_attempts
        raise
      else
        attempt_counter += 1
        sleep 1
        retry
      end
    else
      raise
    end
  end
end

#lock_for_update(key, timeout = 60, max_attempts = 100) ⇒ Object

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



15
16
17
18
19
20
21
# 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 = yield if block_given?
    self.unlock(key)
    return response
  end
end

#unlock(key) ⇒ Object

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

Example:

$redis.unlock(‘beers_on_the_wall’)



66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/redis/lock.rb', line 66

def unlock(key)
  current_lock_key = lock_key(key)
  lock_value = self.get(current_lock_key)
  return true unless lock_value
  lock_timeout, lock_holder = lock_value.split('-')
  if (lock_timeout.to_i > Time.now.to_i) && (lock_holder.to_i == Process.pid)
    self.del(current_lock_key)
    return true
  else
    return false
  end
end