Module: Interlock::Lock

Defined in:
lib/interlock/lock.rb

Instance Method Summary collapse

Instance Method Details

#lock(key, lock_expiry = 30, retries = 5) ⇒ Object

Try to acquire a global lock from memcached for a particular key. If successful, yield and set the key to the return value, then release the lock.

Based on rubyurl.com/Sw7 , which I partially wrote.

Raises:



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/interlock/lock.rb', line 13

def lock(key, lock_expiry = 30, retries = 5)
  retries.times do |count|
  
    # We have to be compatible with both client APIs. Eventually we can use Memcached#cas 
    # for this.        
    begin
      response = CACHE.add("lock:#{key}", "Locked by #{Process.pid}", lock_expiry)
      # Nil is a successful response for Memcached 0.11, and "STORED\r\n" for MemCache.
      response = [true, nil, "STORED\r\n"].include?(response)
    rescue Memcached::NotStored 
      # Do nothing
    end
    
    if response
      begin
        value = yield(CACHE.get(key))
        CACHE.set(key, value)
        return value
      ensure 
        CACHE.delete("lock:#{key}")
      end
    else
      # Wait
      sleep((2**count) / 2.0)
    end
  end
  
  raise ::Interlock::LockAcquisitionError, "Couldn't acquire lock for #{key}"
end