Skip to content

Instantly share code, notes, and snippets.

@torkale
Created May 21, 2012 12:13
Show Gist options
  • Save torkale/2762063 to your computer and use it in GitHub Desktop.
Save torkale/2762063 to your computer and use it in GitHub Desktop.
Distributed lock using rails cache
require 'active_support/all'
require 'timeout'
class CacheMutex
INTERVAL = 0.01
TIMEOUT = 20
def initialize(name)
@name = name
@have_lock = false
end
def lock
acquire
yield
ensure
release
end
protected
def acquire
return if @have_lock
sleep_lock
cache.write(key, 1, :expires_in => 1.minute)
@have_lock = true
end
def sleep_lock
iteration = 0
while cache.exist?(key)
duration = CacheMutex.sleep_duration( iteration += 1 )
raise Timeout::Error if duration > TIMEOUT
sleep duration
end
end
def self.sleep_duration(iteration)
2 ** iteration * INTERVAL
end
def cache
Rails.cache
end
def key
"LOCK-#{@name}"
end
def release
if @have_lock
cache.delete key
@have_lock = false
end
end
end
require "./lib/cache_mutex.rb"
describe CacheMutex do
class CacheMock
def initialize
@data = {}
end
def write(k, v, options ={})
@data[k] = v
end
def exist?(k)
@data.key? k
end
def delete(k)
@data.delete(k)
end
end
let :cache do
CacheMock.new
end
def cache_mutex
cm = CacheMutex.new("foo")
cm.stub(:cache => cache)
cm
end
subject do
cache_mutex
end
it "locks around the block" do
subject.lock do
subject.instance_variable_get(:@have_lock).should == true
end
subject.instance_variable_get(:@have_lock).should == false
end
it "returns the value of the inner block" do
subject.lock{1}.should == 1
end
it "has it's own lock" do
subject.lock do
subject.lock do
end
end
end
it "does not have other mutex' lock" do
CacheMutex.stub(:sleep_duration => 21)
expect do
subject.lock do
cache_mutex.lock do
end
end
end.to raise_error Timeout::Error
end
it "releases the key for other mutex" do
expect do
subject.lock do
end
cache_mutex.lock do
end
end.not_to raise_error
end
it "calculates sleep_duration right" do
CacheMutex.sleep_duration(5).should == 2 ** 5 * 0.01
end
end
@grosser
Copy link

grosser commented Nov 24, 2015

FYI this seems to be pretty good ... also does not have the same read/write race condition

https://github.com/smira/memcache-lock

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment