class Arturo::FeatureCaching::AllStrategy
Public Class Methods
expire(cache, symbol)
click to toggle source
# File lib/arturo/feature_caching.rb, line 84 def expire(cache, symbol) cache.delete("arturo.all") end
fetch(cache, symbol, &block)
click to toggle source
@param cache [Arturo::Cache] cache backend @param symbol [Symbol] arturo identifier @return [Arturo::Feature, Arturo::NoSuchFeature
]
# File lib/arturo/feature_caching.rb, line 70 def fetch(cache, symbol, &block) existing_features = cache.read("arturo.all") features = if cache_is_current?(cache, existing_features) existing_features else arturos_from_origin(fallback: existing_features).tap do |updated_features| update_and_extend_cache!(cache, updated_features) end end features[symbol] || Arturo::NoSuchFeature.new(symbol) end
register_cache_update_listener(&block)
click to toggle source
# File lib/arturo/feature_caching.rb, line 88 def register_cache_update_listener(&block) cache_update_listeners << block end
Private Class Methods
arturos_from_origin(fallback:)
click to toggle source
@param fallback [Hash] features to use on database failure @return [Hash] updated features from origin or fallback @raise [ActiveRecord::ActiveRecordError] on database failure
without cache extension option
# File lib/arturo/feature_caching.rb, line 104 def arturos_from_origin(fallback:) Arturo::Feature.all.to_h { |f| [f.symbol.to_sym, f] } rescue ActiveRecord::ActiveRecordError raise unless Arturo::Feature.extend_cache_on_failure? if fallback.blank? log_empty_cache raise else log_stale_cache fallback end end
cache_is_current?(cache, features)
click to toggle source
@return [Boolean] whether the current cache has to be updated from origin @raise [ActiveRecord::ActiveRecordError] on database failure
without cache extension option
# File lib/arturo/feature_caching.rb, line 123 def cache_is_current?(cache, features) return unless features return true if cache.read("arturo.current") begin return false if origin_changed?(features) rescue ActiveRecord::ActiveRecordError raise unless Arturo::Feature.extend_cache_on_failure? if features.blank? log_empty_cache raise else log_stale_cache update_and_extend_cache!(cache, features) end return true end mark_as_current!(cache) end
cache_update_listeners()
click to toggle source
# File lib/arturo/feature_caching.rb, line 94 def cache_update_listeners @cache_update_listeners ||= [] end
formatted_log(namespace, msg)
click to toggle source
# File lib/arturo/feature_caching.rb, line 145 def formatted_log(namespace, msg) "[Arturo][#{namespace}] #{msg}" end
log_empty_cache()
click to toggle source
# File lib/arturo/feature_caching.rb, line 149 def log_empty_cache Arturo.logger.error(formatted_log('extend_cache_on_failure', 'Fallback cache is empty')) end
log_stale_cache()
click to toggle source
# File lib/arturo/feature_caching.rb, line 153 def log_stale_cache Arturo.logger.warn(formatted_log('extend_cache_on_failure', 'Falling back to stale cache')) end
mark_as_current!(cache)
click to toggle source
@return [True]
# File lib/arturo/feature_caching.rb, line 160 def mark_as_current!(cache) cache.write("arturo.current", true, expires_in: Arturo::Feature.cache_ttl) end
origin_changed?(features)
click to toggle source
The Arturo
origin might return a big payload, so checking for the latest update is a cheaper operation.
@return [Boolean] if origin has been updated since the last cache update.
# File lib/arturo/feature_caching.rb, line 170 def origin_changed?(features) features.values.map(&:updated_at).compact.max != Arturo::Feature.maximum(:updated_at) end
update_and_extend_cache!(cache, features)
click to toggle source
# File lib/arturo/feature_caching.rb, line 174 def update_and_extend_cache!(cache, features) mark_as_current!(cache) cache.write("arturo.all", features, expires_in: Arturo::Feature.cache_ttl * 10) cache_update_listeners.each(&:call) end