Class: LaunchDarkly::Integrations::Util::CachingStoreWrapper

Inherits:
Object
  • Object
show all
Includes:
LaunchDarkly::Interfaces::FeatureStore
Defined in:
lib/ldclient-rb/integrations/util/store_wrapper.rb

Overview

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.

Since:

  • 5.5.0

Instance Method Summary collapse

Constructor Details

#initialize(core, opts) ⇒ CachingStoreWrapper

Creates a new store wrapper instance.

Parameters:

  • core (Object)

    an object that implements the FeatureStoreCore methods

  • opts (Hash)

    a hash that may include cache-related options; all others will be ignored

Options Hash (opts):

  • :expiration (Float) — default: 15

    cache TTL; zero means no caching

  • :capacity (Integer) — default: 1000

    maximum number of items in the cache

Since:

  • 5.5.0



35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/ldclient-rb/integrations/util/store_wrapper.rb', line 35

def initialize(core, opts)
  @core = core

  expiration_seconds = opts[:expiration] || 15
  if expiration_seconds > 0
    capacity = opts[:capacity] || 1000
    @cache = Impl::ExpiringCache.new(capacity, expiration_seconds)
  else
    @cache = nil
  end

  @inited = Concurrent::AtomicBoolean.new(false)
  @has_available_method = @core.respond_to? :available?
end

Instance Method Details

#all(kind) ⇒ Object

Since:

  • 5.5.0



91
92
93
94
95
96
97
98
99
100
101
# File 'lib/ldclient-rb/integrations/util/store_wrapper.rb', line 91

def all(kind)
  cache = @cache
  unless cache.nil?
    items = cache[all_cache_key(kind)]
    return items unless items.nil?
  end

  items = items_if_not_deleted(@core.get_all_internal(kind))
  cache[all_cache_key(kind)] = items unless cache.nil?
  items
end

#available?Boolean

Returns:

  • (Boolean)

Since:

  • 5.5.0



54
55
56
57
58
# File 'lib/ldclient-rb/integrations/util/store_wrapper.rb', line 54

def available?
  return false unless @has_available_method

  @core.available?
end

#delete(kind, key, version) ⇒ Object

Since:

  • 5.5.0



113
114
115
# File 'lib/ldclient-rb/integrations/util/store_wrapper.rb', line 113

def delete(kind, key, version)
  upsert(kind, { key: key, version: version, deleted: true })
end

#disable_cachevoid

This method returns an undefined value.

Disable the in-memory cache. Releases the cache reference so subsequent operations bypass it and go directly to the underlying core. Safe to call multiple times.

Called by the FDv2 store coordinator once the in-memory store has become the source of truth and the persistent-store cache is no longer useful. Internal – not part of the public API.

Since:

  • 5.5.0



145
146
147
148
149
150
# File 'lib/ldclient-rb/integrations/util/store_wrapper.rb', line 145

def disable_cache
  cache = @cache
  return if cache.nil?
  @cache = nil
  cache.clear
end

#get(kind, key) ⇒ Object

Since:

  • 5.5.0



76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/ldclient-rb/integrations/util/store_wrapper.rb', line 76

def get(kind, key)
  cache = @cache
  cache_key = item_cache_key(kind, key)
  unless cache.nil?
    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]) unless cached.nil?
  end

  item = @core.get_internal(kind, key)

  cache[cache_key] = [item] unless cache.nil?

  item_if_not_deleted(item)
end

#init(all_data) ⇒ Object

Since:

  • 5.5.0



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/ldclient-rb/integrations/util/store_wrapper.rb', line 60

def init(all_data)
  @core.init_internal(all_data)
  @inited.make_true

  cache = @cache
  unless 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

#initialized?Boolean

Returns:

  • (Boolean)

Since:

  • 5.5.0



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/ldclient-rb/integrations/util/store_wrapper.rb', line 117

def initialized?
  return true if @inited.value

  cache = @cache
  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

#monitoring_enabled?Boolean

Returns:

  • (Boolean)

Since:

  • 5.5.0



50
51
52
# File 'lib/ldclient-rb/integrations/util/store_wrapper.rb', line 50

def monitoring_enabled?
  @has_available_method
end

#stopObject

Since:

  • 5.5.0



152
153
154
# File 'lib/ldclient-rb/integrations/util/store_wrapper.rb', line 152

def stop
  @core.stop
end

#upsert(kind, item) ⇒ Object

Since:

  • 5.5.0



103
104
105
106
107
108
109
110
111
# File 'lib/ldclient-rb/integrations/util/store_wrapper.rb', line 103

def upsert(kind, item)
  new_state = @core.upsert_internal(kind, item)

  cache = @cache
  unless cache.nil?
    cache[item_cache_key(kind, item[:key])] = [new_state]
    cache.delete(all_cache_key(kind))
  end
end