Skip to content

Instantly share code, notes, and snippets.

@trak3r
Created September 14, 2010 00:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save trak3r/578303 to your computer and use it in GitHub Desktop.
Save trak3r/578303 to your computer and use it in GitHub Desktop.
# 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