-
-
Notifications
You must be signed in to change notification settings - Fork 422
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #848 from flippercloud/dalli-prefix
Cache Improvements
- Loading branch information
Showing
12 changed files
with
478 additions
and
360 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
module Flipper | ||
module Adapters | ||
# Base class for caching adapters. Inherit from this and then override | ||
# cache_fetch, cache_read_multi, cache_write, and cache_delete. | ||
class CacheBase | ||
include ::Flipper::Adapter | ||
|
||
# Public: The adapter being cached. | ||
attr_reader :adapter | ||
|
||
# Public: The ActiveSupport::Cache::Store to cache with. | ||
attr_reader :cache | ||
|
||
# Public: The ttl for all cached data. | ||
attr_reader :ttl | ||
|
||
# Public: The cache key where the set of known features is cached. | ||
attr_reader :features_cache_key | ||
|
||
# Public: Alias expires_in to ttl for compatibility. | ||
alias_method :expires_in, :ttl | ||
|
||
def initialize(adapter, cache, ttl = 300, prefix: nil) | ||
@adapter = adapter | ||
@cache = cache | ||
@ttl = ttl | ||
|
||
@cache_version = 'v1'.freeze | ||
@namespace = "flipper/#{@cache_version}" | ||
@namespace = @namespace.prepend(prefix) if prefix | ||
@features_cache_key = "#{@namespace}/features" | ||
end | ||
|
||
# Public: Expire the cache for the set of known feature names. | ||
def expire_features_cache | ||
cache_delete @features_cache_key | ||
end | ||
|
||
# Public: Expire the cache for a given feature. | ||
def expire_feature_cache(key) | ||
cache_delete feature_cache_key(key) | ||
end | ||
|
||
# Public | ||
def features | ||
read_feature_keys | ||
end | ||
|
||
# Public | ||
def add(feature) | ||
result = @adapter.add(feature) | ||
expire_features_cache | ||
result | ||
end | ||
|
||
# Public | ||
def remove(feature) | ||
result = @adapter.remove(feature) | ||
expire_features_cache | ||
expire_feature_cache(feature.key) | ||
result | ||
end | ||
|
||
# Public | ||
def clear(feature) | ||
result = @adapter.clear(feature) | ||
expire_feature_cache(feature.key) | ||
result | ||
end | ||
|
||
# Public | ||
def get(feature) | ||
read_feature(feature) | ||
end | ||
|
||
# Public | ||
def get_multi(features) | ||
read_many_features(features) | ||
end | ||
|
||
# Public | ||
def get_all | ||
features = read_feature_keys.map { |key| Flipper::Feature.new(key, self) } | ||
read_many_features(features) | ||
end | ||
|
||
# Public | ||
def enable(feature, gate, thing) | ||
result = @adapter.enable(feature, gate, thing) | ||
expire_feature_cache(feature.key) | ||
result | ||
end | ||
|
||
# Public | ||
def disable(feature, gate, thing) | ||
result = @adapter.disable(feature, gate, thing) | ||
expire_feature_cache(feature.key) | ||
result | ||
end | ||
|
||
# Public: Generate the cache key for a given feature. | ||
# | ||
# key - The String or Symbol feature key. | ||
def feature_cache_key(key) | ||
"#{@namespace}/feature/#{key}" | ||
end | ||
|
||
private | ||
|
||
# Private: Returns the Set of known feature keys. | ||
def read_feature_keys | ||
cache_fetch(@features_cache_key) { @adapter.features } | ||
end | ||
|
||
# Private: Read through caching for a single feature. | ||
def read_feature(feature) | ||
cache_fetch(feature_cache_key(feature.key)) { @adapter.get(feature) } | ||
end | ||
|
||
# Private: Given an array of features, attempts to read through cache in | ||
# as few network calls as possible. | ||
def read_many_features(features) | ||
keys = features.map { |feature| feature_cache_key(feature.key) } | ||
cache_result = cache_read_multi(keys) | ||
uncached_features = features.reject { |feature| cache_result[feature_cache_key(feature)] } | ||
|
||
if uncached_features.any? | ||
response = @adapter.get_multi(uncached_features) | ||
response.each do |key, value| | ||
cache_write feature_cache_key(key), value | ||
cache_result[feature_cache_key(key)] = value | ||
end | ||
end | ||
|
||
result = {} | ||
features.each do |feature| | ||
result[feature.key] = cache_result[feature_cache_key(feature.key)] | ||
end | ||
result | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.