Skip to content

Instantly share code, notes, and snippets.

@joegaudet
Created January 17, 2018 00:11
Show Gist options
  • Save joegaudet/2c9b9e517f6e99829e304e7958f85105 to your computer and use it in GitHub Desktop.
Save joegaudet/2c9b9e517f6e99829e304e7958f85105 to your computer and use it in GitHub Desktop.
def redis_queued_mutex(type, key, options ={})
# our tests are single threaded so
if Rails.env.test?
yield
else
# define the maximum number of times we will wait to prevent starvation
max_waits = options[:max_waits] || 500
# amount of time we will sleep waiting for the mutex to clear
sleep_for = (options[:sleep_for] || rand(100..200)/1000.0)
# In the locks namespace
with_redis('queued_locks') do |redis|
id = SecureRandom.urlsafe_base64(12)
# key for this lock
key = "#{type}##{key}"
waits = 0
redis.lpush(key, id)
until redis.lindex(0) == id
sleep sleep_for
waits += 1
if waits == max_waits
raise "Exceeded the maximum number of waits for lock #{type}:#{key}"
end
end
begin
# this is where the mutex code is actually run
yield
ensure
# no matter what happens lets pop out our entry
redis.lpop(key, id)
# sleep just incase we are in a loop or something, allowing other processes to
# claim the lock
sleep sleep_for
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment