module LockAndCache
Lock and cache using redis!
Most caching libraries don't do locking, meaning that >1 process can be calculating a cached value at the same time. Since you presumably cache things because they cost CPU, database reads, or money, doesn't it make sense to lock while caching?
Constants
- DEFAULT_HEARTBEAT_EXPIRES
- DEFAULT_MAX_LOCK_WAIT
- VERSION
Public Class Methods
@return [Redis] The redis connection used for cached value storage
# File lib/lock_and_cache.rb, line 41 def LockAndCache.cache_storage @cache_storage end
@param redis_connection [Redis] A redis connection to be used for cached value storage
# File lib/lock_and_cache.rb, line 35 def LockAndCache.cache_storage=(redis_connection) raise "only redis for now" unless redis_connection.class.to_s == 'Redis' @cache_storage = redis_connection end
Check if a key is cached already
@note Standalone mode. See also “context mode,” where you mix LockAndCache
into a class and call it from within its methods.
# File lib/lock_and_cache.rb, line 107 def LockAndCache.cached?(*key_parts) key = LockAndCache::Key.new key_parts key.cached? end
Clear a single key
@note Standalone mode. See also “context mode,” where you mix LockAndCache
into a class and call it from within its methods.
# File lib/lock_and_cache.rb, line 91 def LockAndCache.clear(*key_parts) key = LockAndCache::Key.new key_parts key.clear end
Flush LockAndCache's cached value storage.
@note If you are sharing a redis database, it will clear it…
@note If you want to clear a single key, try `LockAndCache.clear(key)` (standalone mode) or `#lock_and_cache_clear(method_id, *key_parts)` in context mode.
# File lib/lock_and_cache.rb, line 60 def LockAndCache.flush_cache cache_storage.flushdb end
Flush LockAndCache's lock storage.
@note If you are sharing a redis database, it will clear it…
@note If you want to clear a single key, try `LockAndCache.clear(key)` (standalone mode) or `#lock_and_cache_clear(method_id, *key_parts)` in context mode.
# File lib/lock_and_cache.rb, line 69 def LockAndCache.flush_locks lock_storage.flushdb end
@private
# File lib/lock_and_cache.rb, line 134 def LockAndCache.heartbeat_expires @heartbeat_expires || DEFAULT_HEARTBEAT_EXPIRES end
@param seconds [Numeric] How often a process has to heartbeat in order to keep a lock
@note Can be overridden by putting `heartbeat_expires:` in your call to `#lock_and_cache`
# File lib/lock_and_cache.rb, line 127 def LockAndCache.heartbeat_expires=(seconds) memo = seconds.to_f raise "heartbeat_expires must be greater than 2 seconds" unless memo >= 2 @heartbeat_expires = memo end
Lock and cache based on a key.
@param key_parts [*] Parts that should be used to construct a key.
@note Standalone mode. See also “context mode,” where you mix LockAndCache
into a class and call it from within its methods.
@note A single hash arg is treated as a cache key, e.g. `LockAndCache.lock_and_cache(foo: :bar, expires: 100)` will be treated as a cache key of `foo: :bar, expires: 100` (which is probably wrong!!!). Try `LockAndCache.lock_and_cache({ foo: :bar }, expires: 100)` instead. This is the opposite of context mode.
# File lib/lock_and_cache.rb, line 80 def LockAndCache.lock_and_cache(*key_parts_and_options, &blk) options = (key_parts_and_options.last.is_a?(Hash) && key_parts_and_options.length > 1) ? key_parts_and_options.pop : {} raise "need a cache key" unless key_parts_and_options.length > 0 key = LockAndCache::Key.new key_parts_and_options action = LockAndCache::Action.new key, options, blk action.perform end
@return [Redis] The redis connection used for lock and cached value storage
# File lib/lock_and_cache.rb, line 30 def LockAndCache.lock_storage @lock_storage end
@param redis_connection [Redis] A redis connection to be used for lock storage
# File lib/lock_and_cache.rb, line 24 def LockAndCache.lock_storage=(redis_connection) raise "only redis for now" unless redis_connection.class.to_s == 'Redis' @lock_storage = redis_connection end
Check if a key is locked
@note Standalone mode. See also “context mode,” where you mix LockAndCache
into a class and call it from within its methods.
# File lib/lock_and_cache.rb, line 99 def LockAndCache.locked?(*key_parts) key = LockAndCache::Key.new key_parts key.locked? end
@return [Logger] The logger.
# File lib/lock_and_cache.rb, line 51 def LockAndCache.logger @logger end
@param logger [Logger] A logger.
# File lib/lock_and_cache.rb, line 46 def LockAndCache.logger=(logger) @logger = logger end
@private
# File lib/lock_and_cache.rb, line 120 def LockAndCache.max_lock_wait @max_lock_wait || DEFAULT_MAX_LOCK_WAIT end
@param seconds [Numeric] Maximum wait time to get a lock
@note Can be overridden by putting `max_lock_wait:` in your call to `#lock_and_cache`
# File lib/lock_and_cache.rb, line 115 def LockAndCache.max_lock_wait=(seconds) @max_lock_wait = seconds.to_f end
Public Instance Methods
Lock and cache a method given key parts.
The cache key will automatically include the class name of the object calling it (the context!) and the name of the method it is called from.
@param key_parts_and_options [*] Parts that you want to include in the lock and cache key. If the last element is a Hash, it will be treated as options.
@return The cached value (possibly newly calculated).
@note Subject mode - this is expected to be called on an object whose class has LockAndCache
mixed in. See also standalone mode.
@note A single hash arg is treated as an options hash, e.g. `lock_and_cache(expires: 100)` will be treated as options `expires: 100`. This is the opposite of standalone mode.
# File lib/lock_and_cache.rb, line 165 def lock_and_cache(*key_parts_and_options, &blk) options = key_parts_and_options.last.is_a?(Hash) ? key_parts_and_options.pop : {} key = LockAndCache::Key.new key_parts_and_options, context: self, caller: caller action = LockAndCache::Action.new key, options, blk action.perform end
Clear a lock and cache given exactly the method and exactly the same arguments
@note Subject mode - this is expected to be called on an object whose class has LockAndCache
mixed in. See also standalone mode.
# File lib/lock_and_cache.rb, line 149 def lock_and_cache_clear(method_id, *key_parts) key = LockAndCache::Key.new key_parts, context: self, method_id: method_id key.clear end
Check if a method is locked on an object.
@note Subject mode - this is expected to be called on an object whose class has LockAndCache
mixed in. See also standalone mode.
# File lib/lock_and_cache.rb, line 141 def lock_and_cache_locked?(method_id, *key_parts) key = LockAndCache::Key.new key_parts, context: self, method_id: method_id key.locked? end