Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
# back-port the bypass_local_cache feature from activesupport 3.0.0
module ActiveSupport
module Cache
class MemoryStore
def bypass_local_cache
yield
end
end
module Strategy
module LocalCache
protected
def bypass_local_cache
save_cache = Thread.current[thread_local_key]
begin
Thread.current[thread_local_key] = nil
yield
ensure
Thread.current[thread_local_key] = save_cache
end
end
end
end
end
end
module WaitForCache
class Lock
def initialize(thread_id_override_for_testing = nil)
@thread_id = thread_id_override_for_testing || Process.pid
end
def mine?
Process.pid == @thread_id
end
def to_s
@thread_id.to_s
end
end
def log(key, msg)
Rails.logger.add(3, "WaitForCache(#{Process.pid}): #{msg}")
end
def wait_for_cache(key, attempt_count = 0, &block)
# get value from cache
value = Rails.cache.send(:bypass_local_cache) { Rails.cache.read(key) }
if value.nil?
# value is nil
if 0 < attempt_count
# something is f'ed up; the cache might be broken
log(key,"*** Failed to lock")
block.call
else
# "add" my lock object into the cache
log(key,"Locking")
Rails.cache.write(key, Lock.new, :unless_exist => true)
# (will fail if somebody beats me, and that's OK)
# recurse
wait_for_cache(key, 1+attempt_count, &block)
end
elsif value.kind_of?(Lock)
# value is a lock object
if value.mine?
# lock object is mine
# data = yield block
log(key,"Calling")
value = block.call
# "set" data into cache (replaces the lock object)
log(key,"Caching")
Rails.cache.write(key, value)
# return query data (or recurse if you want to be pure)
wait_for_cache(key, attempt_count, &block)
else
# lock object is somebody else's
if 5 > attempt_count
# i've not retried three times yet
# sleep for a little bit
log(key,"Sleeping (locked by #{value})")
sleep(1.0) # seconds
# increment retry count
# recurse
wait_for_cache(key, 1 + attempt_count, &block)
else
# this is the third time i've tried
# (they are taking too long or might have died)
# replace lock object with nil
log(key,"*** Killing")
Rails.cache.write(key, nil)
# reset retry count
# recurse
wait_for_cache(key, 0, &block)
end
end
else
# value is data
# return data
log(key,"Got cached data")
value
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.