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.



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