public
Last active

  • Download Gist
wait_for_cache.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
# 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

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.