class LaunchDarkly::Integrations::Util::CachingStoreWrapper
CachingStoreWrapper
is a partial implementation of the {LaunchDarkly::Interfaces::FeatureStore} pattern that delegates part of its behavior to another object, while providing optional caching behavior and other logic that would otherwise be repeated in every feature store implementation. This makes it easier to create new database integrations by implementing only the database-specific logic.
The mixin {FeatureStoreCore} describes the methods that need to be supported by the inner implementation object.
Public Class Methods
Creates a new store wrapper instance.
@param core [Object] an object that implements the {FeatureStoreCore} methods @param opts [Hash] a hash that may include cache-related options; all others will be ignored @option opts [Float] :expiration (15) cache TTL; zero means no caching @option opts [Integer] :capacity (1000) maximum number of items in the cache
# File lib/ldclient-rb/integrations/util/store_wrapper.rb, line 29 def initialize(core, opts) @core = core expiration_seconds = opts[:expiration] || 15 if expiration_seconds > 0 capacity = opts[:capacity] || 1000 @cache = ExpiringCache.new(capacity, expiration_seconds) else @cache = nil end @inited = Concurrent::AtomicBoolean.new(false) end
Public Instance Methods
# File lib/ldclient-rb/integrations/util/store_wrapper.rb, line 74 def all(kind) if !@cache.nil? items = @cache[all_cache_key(kind)] return items if !items.nil? end items = items_if_not_deleted(@core.get_all_internal(kind)) @cache[all_cache_key(kind)] = items if !@cache.nil? items end
# File lib/ldclient-rb/integrations/util/store_wrapper.rb, line 94 def delete(kind, key, version) upsert(kind, { key: key, version: version, deleted: true }) end
# File lib/ldclient-rb/integrations/util/store_wrapper.rb, line 58 def get(kind, key) if !@cache.nil? cache_key = item_cache_key(kind, key) cached = @cache[cache_key] # note, item entries in the cache are wrapped in an array so we can cache nil values return item_if_not_deleted(cached[0]) if !cached.nil? end item = @core.get_internal(kind, key) if !@cache.nil? @cache[cache_key] = [item] end item_if_not_deleted(item) end
# File lib/ldclient-rb/integrations/util/store_wrapper.rb, line 43 def init(all_data) @core.init_internal(all_data) @inited.make_true if !@cache.nil? @cache.clear all_data.each do |kind, items| @cache[kind] = items_if_not_deleted(items) items.each do |key, item| @cache[item_cache_key(kind, key)] = [item] end end end end
# File lib/ldclient-rb/integrations/util/store_wrapper.rb, line 98 def initialized? return true if @inited.value if @cache.nil? result = @core.initialized_internal? else result = @cache[inited_cache_key] if result.nil? result = @core.initialized_internal? @cache[inited_cache_key] = result end end @inited.make_true if result result end
# File lib/ldclient-rb/integrations/util/store_wrapper.rb, line 115 def stop @core.stop end
# File lib/ldclient-rb/integrations/util/store_wrapper.rb, line 85 def upsert(kind, item) new_state = @core.upsert_internal(kind, item) if !@cache.nil? @cache[item_cache_key(kind, item[:key])] = [new_state] @cache.delete(all_cache_key(kind)) end end
Private Instance Methods
The result of a call to get_all_internal is cached using the “kind” object as a key.
# File lib/ldclient-rb/integrations/util/store_wrapper.rb, line 127 def all_cache_key(kind) kind end
The result of initialized_internal? is cached using this key.
# File lib/ldclient-rb/integrations/util/store_wrapper.rb, line 132 def inited_cache_key "$inited" end
We use just one cache for 3 kinds of objects. Individual entities use a key like 'features:my-flag'.
# File lib/ldclient-rb/integrations/util/store_wrapper.rb, line 122 def item_cache_key(kind, key) kind[:namespace] + ":" + key.to_s end
# File lib/ldclient-rb/integrations/util/store_wrapper.rb, line 136 def item_if_not_deleted(item) (item.nil? || item[:deleted]) ? nil : item end
# File lib/ldclient-rb/integrations/util/store_wrapper.rb, line 140 def items_if_not_deleted(items) items.select { |key, item| !item[:deleted] } end