flipper-dalli 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/flipper/adapters/dalli.rb +13 -108
- data/lib/flipper/version.rb +1 -1
- data/spec/flipper/adapters/dalli_spec.rb +72 -4
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 960ecc222c7e5c33b7837cca5d48f2ae5039cc050301977d3b14dfd94d9c6081
|
4
|
+
data.tar.gz: e759cb6f88b00a59265e9d7084046afa6e1f37b5321ab65f12ecdc9403490733
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c0c0a121101433f3cdac3cf3d58921fd03bfecc406cd642d00b527be8b359a657216afd37c72b0873e80d40cb070786c83e20ce6abcf036448cece9d3b8a788
|
7
|
+
data.tar.gz: 1cf7e3aec7f903bd74e4b1b55e931ca09acb35e7c1eb64114f6ee52d1698a4efb8f632f5953e5956a07d07e00af40e08328599902fba742e2ecee8f7085e862d
|
@@ -1,127 +1,32 @@
|
|
1
1
|
require 'dalli'
|
2
2
|
require 'flipper'
|
3
|
+
require 'flipper/adapters/cache_base'
|
3
4
|
|
4
5
|
module Flipper
|
5
6
|
module Adapters
|
6
7
|
# Public: Adapter that wraps another adapter with the ability to cache
|
7
8
|
# adapter calls in Memcached using the Dalli gem.
|
8
|
-
class Dalli
|
9
|
-
|
10
|
-
|
11
|
-
# Internal
|
12
|
-
attr_reader :cache
|
13
|
-
|
14
|
-
# Public: The ttl for all cached data.
|
15
|
-
attr_reader :ttl
|
16
|
-
|
17
|
-
# Public
|
18
|
-
def initialize(adapter, cache, ttl = 0)
|
19
|
-
@adapter = adapter
|
20
|
-
@cache = cache
|
21
|
-
@ttl = ttl
|
22
|
-
|
23
|
-
@cache_version = 'v1'.freeze
|
24
|
-
@namespace = "flipper/#{@cache_version}".freeze
|
25
|
-
@features_key = "#{@namespace}/features".freeze
|
26
|
-
@get_all_key = "#{@namespace}/get_all".freeze
|
27
|
-
end
|
28
|
-
|
29
|
-
# Public
|
30
|
-
def features
|
31
|
-
read_feature_keys
|
32
|
-
end
|
33
|
-
|
34
|
-
# Public
|
35
|
-
def add(feature)
|
36
|
-
result = @adapter.add(feature)
|
37
|
-
@cache.delete(@features_key)
|
38
|
-
result
|
39
|
-
end
|
40
|
-
|
41
|
-
# Public
|
42
|
-
def remove(feature)
|
43
|
-
result = @adapter.remove(feature)
|
44
|
-
@cache.delete(@features_key)
|
45
|
-
@cache.delete(key_for(feature.key))
|
46
|
-
result
|
47
|
-
end
|
48
|
-
|
49
|
-
# Public
|
50
|
-
def clear(feature)
|
51
|
-
result = @adapter.clear(feature)
|
52
|
-
@cache.delete(key_for(feature.key))
|
53
|
-
result
|
54
|
-
end
|
55
|
-
|
56
|
-
# Public
|
57
|
-
def get(feature)
|
58
|
-
@cache.fetch(key_for(feature.key), @ttl) do
|
59
|
-
@adapter.get(feature)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def get_multi(features)
|
64
|
-
read_many_features(features)
|
65
|
-
end
|
66
|
-
|
67
|
-
def get_all
|
68
|
-
if @cache.add(@get_all_key, Time.now.to_i, @ttl)
|
69
|
-
response = @adapter.get_all
|
70
|
-
response.each do |key, value|
|
71
|
-
@cache.set(key_for(key), value, @ttl)
|
72
|
-
end
|
73
|
-
@cache.set(@features_key, response.keys.to_set, @ttl)
|
74
|
-
response
|
75
|
-
else
|
76
|
-
features = read_feature_keys.map { |key| Flipper::Feature.new(key, self) }
|
77
|
-
read_many_features(features)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Public
|
82
|
-
def enable(feature, gate, thing)
|
83
|
-
result = @adapter.enable(feature, gate, thing)
|
84
|
-
@cache.delete(key_for(feature.key))
|
85
|
-
result
|
86
|
-
end
|
87
|
-
|
88
|
-
# Public
|
89
|
-
def disable(feature, gate, thing)
|
90
|
-
result = @adapter.disable(feature, gate, thing)
|
91
|
-
@cache.delete(key_for(feature.key))
|
92
|
-
result
|
9
|
+
class Dalli < CacheBase
|
10
|
+
def initialize(adapter, cache, ttl = 0, prefix: nil)
|
11
|
+
super
|
93
12
|
end
|
94
13
|
|
95
14
|
private
|
96
15
|
|
97
|
-
def
|
98
|
-
|
16
|
+
def cache_fetch(key, &block)
|
17
|
+
@cache.fetch(key, @ttl, &block)
|
99
18
|
end
|
100
19
|
|
101
|
-
def
|
102
|
-
@cache.
|
20
|
+
def cache_read_multi(keys)
|
21
|
+
@cache.get_multi(keys)
|
103
22
|
end
|
104
23
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
keys = features.map { |feature| key_for(feature.key) }
|
109
|
-
cache_result = @cache.get_multi(keys)
|
110
|
-
uncached_features = features.reject { |feature| cache_result[key_for(feature.key)] }
|
111
|
-
|
112
|
-
if uncached_features.any?
|
113
|
-
response = @adapter.get_multi(uncached_features)
|
114
|
-
response.each do |key, value|
|
115
|
-
@cache.set(key_for(key), value, @ttl)
|
116
|
-
cache_result[key_for(key)] = value
|
117
|
-
end
|
118
|
-
end
|
24
|
+
def cache_write(key, value)
|
25
|
+
@cache.set(key, value, @ttl)
|
26
|
+
end
|
119
27
|
|
120
|
-
|
121
|
-
|
122
|
-
result[feature.key] = cache_result[key_for(feature.key)]
|
123
|
-
end
|
124
|
-
result
|
28
|
+
def cache_delete(key)
|
29
|
+
@cache.delete(key)
|
125
30
|
end
|
126
31
|
end
|
127
32
|
end
|
data/lib/flipper/version.rb
CHANGED
@@ -7,7 +7,7 @@ RSpec.describe Flipper::Adapters::Dalli do
|
|
7
7
|
Flipper::Adapters::OperationLogger.new(Flipper::Adapters::Memory.new)
|
8
8
|
end
|
9
9
|
let(:cache) { Dalli::Client.new(ENV['MEMCACHED_URL']) }
|
10
|
-
let(:adapter) { described_class.new(memory_adapter, cache) }
|
10
|
+
let(:adapter) { described_class.new(memory_adapter, cache, 10) }
|
11
11
|
let(:flipper) { Flipper.new(adapter) }
|
12
12
|
|
13
13
|
subject { adapter }
|
@@ -21,6 +21,72 @@ RSpec.describe Flipper::Adapters::Dalli do
|
|
21
21
|
|
22
22
|
it_should_behave_like 'a flipper adapter'
|
23
23
|
|
24
|
+
it "knows ttl" do
|
25
|
+
expect(adapter.ttl).to eq(10)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "knows features_cache_key" do
|
29
|
+
expect(adapter.features_cache_key).to eq("flipper/v1/features")
|
30
|
+
end
|
31
|
+
|
32
|
+
it "can expire features cache" do
|
33
|
+
# cache the features
|
34
|
+
adapter.features
|
35
|
+
expect(cache.get("flipper/v1/features")).not_to be(nil)
|
36
|
+
|
37
|
+
# expire cache
|
38
|
+
adapter.expire_features_cache
|
39
|
+
expect(cache.get("flipper/v1/features")).to be(nil)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can expire feature cache" do
|
43
|
+
# cache the features
|
44
|
+
adapter.get(flipper[:stats])
|
45
|
+
expect(cache.get("flipper/v1/feature/stats")).not_to be(nil)
|
46
|
+
|
47
|
+
# expire cache
|
48
|
+
adapter.expire_feature_cache("stats")
|
49
|
+
expect(cache.get("flipper/v1/feature/stats")).to be(nil)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "can generate feature cache key" do
|
53
|
+
expect(adapter.feature_cache_key("stats")).to eq("flipper/v1/feature/stats")
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when using a prefix" do
|
57
|
+
let(:adapter) { described_class.new(memory_adapter, cache, 0, prefix: "foo/") }
|
58
|
+
it_should_behave_like 'a flipper adapter'
|
59
|
+
|
60
|
+
it "knows features_cache_key" do
|
61
|
+
expect(adapter.features_cache_key).to eq("foo/flipper/v1/features")
|
62
|
+
end
|
63
|
+
|
64
|
+
it "can generate feature cache key" do
|
65
|
+
expect(adapter.feature_cache_key("stats")).to eq("foo/flipper/v1/feature/stats")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "uses the prefix for all keys" do
|
69
|
+
# check individual feature get cached with prefix
|
70
|
+
adapter.get(flipper[:stats])
|
71
|
+
expect(cache.get("foo/flipper/v1/feature/stats")).not_to be(nil)
|
72
|
+
|
73
|
+
# check individual feature expired with prefix
|
74
|
+
adapter.remove(flipper[:stats])
|
75
|
+
expect(cache.get("foo/flipper/v1/feature/stats")).to be(nil)
|
76
|
+
|
77
|
+
# enable some stuff
|
78
|
+
flipper.enable_percentage_of_actors(:search, 10)
|
79
|
+
flipper.enable(:stats)
|
80
|
+
|
81
|
+
# populate the cache
|
82
|
+
adapter.get_all
|
83
|
+
|
84
|
+
# verify cached with prefix
|
85
|
+
expect(cache.get("foo/flipper/v1/feature/search")[:percentage_of_actors]).to eq("10")
|
86
|
+
expect(cache.get("foo/flipper/v1/feature/stats")[:boolean]).to eq("true")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
24
90
|
describe '#remove' do
|
25
91
|
it 'expires feature' do
|
26
92
|
feature = flipper[:stats]
|
@@ -68,17 +134,19 @@ RSpec.describe Flipper::Adapters::Dalli do
|
|
68
134
|
adapter.get_all
|
69
135
|
expect(cache.get("flipper/v1/feature/#{stats.key}")[:boolean]).to eq('true')
|
70
136
|
expect(cache.get("flipper/v1/feature/#{search.key}")[:boolean]).to be(nil)
|
71
|
-
expect(cache.get("flipper/v1/
|
137
|
+
expect(cache.get("flipper/v1/features")).to eq(Set["stats", "search"])
|
72
138
|
end
|
73
139
|
|
74
140
|
it 'returns same result when already cached' do
|
75
141
|
expect(adapter.get_all).to eq(adapter.get_all)
|
76
142
|
end
|
77
143
|
|
78
|
-
it 'only invokes
|
144
|
+
it 'only invokes two calls to wrapped adapter (for features set and gate data for each feature in set)' do
|
79
145
|
memory_adapter.reset
|
80
146
|
5.times { adapter.get_all }
|
81
|
-
expect(memory_adapter.count(:
|
147
|
+
expect(memory_adapter.count(:features)).to eq(1)
|
148
|
+
expect(memory_adapter.count(:get_multi)).to eq(1)
|
149
|
+
expect(memory_adapter.count).to eq(2)
|
82
150
|
end
|
83
151
|
end
|
84
152
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flipper-dalli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Nunemaker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: flipper
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
19
|
+
version: 1.3.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
26
|
+
version: 1.3.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: dalli
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -64,7 +64,7 @@ metadata:
|
|
64
64
|
homepage_uri: https://www.flippercloud.io
|
65
65
|
source_code_uri: https://github.com/flippercloud/flipper
|
66
66
|
bug_tracker_uri: https://github.com/flippercloud/flipper/issues
|
67
|
-
changelog_uri: https://github.com/flippercloud/flipper/releases/tag/v1.
|
67
|
+
changelog_uri: https://github.com/flippercloud/flipper/releases/tag/v1.3.0
|
68
68
|
post_install_message:
|
69
69
|
rdoc_options: []
|
70
70
|
require_paths:
|