flipper-redis 0.26.2 → 1.2.2
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/examples/redis/internals.rb +2 -2
- data/examples/redis/namespaced.rb +2 -2
- data/flipper-redis.gemspec +3 -3
- data/lib/flipper/adapters/redis.rb +37 -22
- data/lib/flipper/adapters/redis_cache.rb +12 -21
- data/lib/flipper/version.rb +11 -1
- data/spec/flipper/adapters/redis_cache_spec.rb +9 -11
- data/spec/flipper/adapters/redis_spec.rb +25 -3
- metadata +13 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e55b034a67c36b705521502c717a6a702e20fe7339571700e7a9250f49f21781
|
4
|
+
data.tar.gz: 95633728475c7a39bd88fd59b17ba4924dbbf9c98e2f7a2b0f196722302b1b19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4cf728abd260addff1b057c68b0ea401458bc53fe8aa1ec4247d322dd1f1083fdbec76d20a4d3fc3bd123c4babde353d5a5be1d66ff07be1881e5430e794d21f
|
7
|
+
data.tar.gz: af6843a3bb222f418ae9917bde9b7d4d9d5f37bcb88371950ad834a7f6d557c0bf7ee8779bcfba8ee57fe6f6144bb1ab928ecbac04fdd3d7290dd70c441f28d0
|
data/examples/redis/internals.rb
CHANGED
@@ -6,8 +6,8 @@ require 'flipper/adapters/redis'
|
|
6
6
|
client = Redis.new
|
7
7
|
|
8
8
|
# Register a few groups.
|
9
|
-
Flipper.register(:admins) { |
|
10
|
-
Flipper.register(:early_access) { |
|
9
|
+
Flipper.register(:admins) { |actor| actor.admin? }
|
10
|
+
Flipper.register(:early_access) { |actor| actor.early_access? }
|
11
11
|
|
12
12
|
# Create a user class that has flipper_id instance method.
|
13
13
|
User = Struct.new(:flipper_id)
|
@@ -12,8 +12,8 @@ adapter = Flipper::Adapters::Redis.new(namespaced_client)
|
|
12
12
|
flipper = Flipper.new(adapter)
|
13
13
|
|
14
14
|
# Register a few groups.
|
15
|
-
Flipper.register(:admins) { |
|
16
|
-
Flipper.register(:early_access) { |
|
15
|
+
Flipper.register(:admins) { |actor| actor.admin? }
|
16
|
+
Flipper.register(:early_access) { |actor| actor.early_access? }
|
17
17
|
|
18
18
|
# Create a user class that has flipper_id instance method.
|
19
19
|
User = Struct.new(:flipper_id)
|
data/flipper-redis.gemspec
CHANGED
@@ -8,10 +8,10 @@ end
|
|
8
8
|
|
9
9
|
Gem::Specification.new do |gem|
|
10
10
|
gem.authors = ['John Nunemaker']
|
11
|
-
gem.email =
|
12
|
-
gem.summary = 'Redis adapter for Flipper'
|
11
|
+
gem.email = 'support@flippercloud.io'
|
12
|
+
gem.summary = 'Redis feature flag adapter for Flipper'
|
13
13
|
gem.license = 'MIT'
|
14
|
-
gem.homepage = 'https://
|
14
|
+
gem.homepage = 'https://www.flippercloud.io/docs/adapters/redis'
|
15
15
|
|
16
16
|
gem.files = `git ls-files`.split("\n").select(&flipper_redis_files) + ['lib/flipper/version.rb']
|
17
17
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n").select(&flipper_redis_files)
|
@@ -7,18 +7,24 @@ module Flipper
|
|
7
7
|
class Redis
|
8
8
|
include ::Flipper::Adapter
|
9
9
|
|
10
|
-
|
11
|
-
FeaturesKey = :flipper_features
|
10
|
+
attr_reader :key_prefix
|
12
11
|
|
13
|
-
|
14
|
-
|
12
|
+
def features_key
|
13
|
+
"#{key_prefix}flipper_features"
|
14
|
+
end
|
15
|
+
|
16
|
+
def key_for(feature_name)
|
17
|
+
"#{key_prefix}#{feature_name}"
|
18
|
+
end
|
15
19
|
|
16
20
|
# Public: Initializes a Redis flipper adapter.
|
17
21
|
#
|
18
|
-
# client - The Redis client to use.
|
19
|
-
|
22
|
+
# client - The Redis client to use.
|
23
|
+
# key_prefix - an optional prefix with which to namespace
|
24
|
+
# flipper's Redis keys
|
25
|
+
def initialize(client, key_prefix: nil)
|
20
26
|
@client = client
|
21
|
-
@
|
27
|
+
@key_prefix = key_prefix
|
22
28
|
end
|
23
29
|
|
24
30
|
# Public: The set of known features.
|
@@ -29,9 +35,9 @@ module Flipper
|
|
29
35
|
# Public: Adds a feature to the set of known features.
|
30
36
|
def add(feature)
|
31
37
|
if redis_sadd_returns_boolean?
|
32
|
-
@client.sadd?
|
38
|
+
@client.sadd? features_key, feature.key
|
33
39
|
else
|
34
|
-
@client.sadd
|
40
|
+
@client.sadd features_key, feature.key
|
35
41
|
end
|
36
42
|
true
|
37
43
|
end
|
@@ -39,17 +45,17 @@ module Flipper
|
|
39
45
|
# Public: Removes a feature from the set of known features.
|
40
46
|
def remove(feature)
|
41
47
|
if redis_sadd_returns_boolean?
|
42
|
-
@client.srem?
|
48
|
+
@client.srem? features_key, feature.key
|
43
49
|
else
|
44
|
-
@client.srem
|
50
|
+
@client.srem features_key, feature.key
|
45
51
|
end
|
46
|
-
@client.del feature.key
|
52
|
+
@client.del key_for(feature.key)
|
47
53
|
true
|
48
54
|
end
|
49
55
|
|
50
56
|
# Public: Clears the gate values for a feature.
|
51
57
|
def clear(feature)
|
52
|
-
@client.del feature.key
|
58
|
+
@client.del key_for(feature.key)
|
53
59
|
true
|
54
60
|
end
|
55
61
|
|
@@ -73,19 +79,22 @@ module Flipper
|
|
73
79
|
# Public: Enables a gate for a given thing.
|
74
80
|
#
|
75
81
|
# feature - The Flipper::Feature for the gate.
|
76
|
-
# gate - The Flipper::Gate to
|
82
|
+
# gate - The Flipper::Gate to enable.
|
77
83
|
# thing - The Flipper::Type being enabled for the gate.
|
78
84
|
#
|
79
85
|
# Returns true.
|
80
86
|
def enable(feature, gate, thing)
|
87
|
+
feature_key = key_for(feature.key)
|
81
88
|
case gate.data_type
|
82
89
|
when :boolean
|
83
90
|
clear(feature)
|
84
|
-
@client.hset
|
91
|
+
@client.hset feature_key, gate.key, thing.value.to_s
|
85
92
|
when :integer
|
86
|
-
@client.hset
|
93
|
+
@client.hset feature_key, gate.key, thing.value.to_s
|
87
94
|
when :set
|
88
|
-
@client.hset
|
95
|
+
@client.hset feature_key, to_field(gate, thing), 1
|
96
|
+
when :json
|
97
|
+
@client.hset feature_key, gate.key, Typecast.to_json(thing.value)
|
89
98
|
else
|
90
99
|
unsupported_data_type gate.data_type
|
91
100
|
end
|
@@ -101,13 +110,16 @@ module Flipper
|
|
101
110
|
#
|
102
111
|
# Returns true.
|
103
112
|
def disable(feature, gate, thing)
|
113
|
+
feature_key = key_for(feature.key)
|
104
114
|
case gate.data_type
|
105
115
|
when :boolean
|
106
|
-
@client.del
|
116
|
+
@client.del feature_key
|
107
117
|
when :integer
|
108
|
-
@client.hset
|
118
|
+
@client.hset feature_key, gate.key, thing.value.to_s
|
109
119
|
when :set
|
110
|
-
@client.hdel
|
120
|
+
@client.hdel feature_key, to_field(gate, thing)
|
121
|
+
when :json
|
122
|
+
@client.hdel feature_key, gate.key
|
111
123
|
else
|
112
124
|
unsupported_data_type gate.data_type
|
113
125
|
end
|
@@ -131,14 +143,14 @@ module Flipper
|
|
131
143
|
end
|
132
144
|
|
133
145
|
def read_feature_keys
|
134
|
-
@client.smembers(
|
146
|
+
@client.smembers(features_key).to_set
|
135
147
|
end
|
136
148
|
|
137
149
|
# Private: Gets a hash of fields => values for the given feature.
|
138
150
|
#
|
139
151
|
# Returns a Hash of fields => values.
|
140
152
|
def doc_for(feature, pipeline: @client)
|
141
|
-
pipeline.hgetall(feature.key)
|
153
|
+
pipeline.hgetall(key_for(feature.key))
|
142
154
|
end
|
143
155
|
|
144
156
|
def docs_for(features)
|
@@ -160,6 +172,9 @@ module Flipper
|
|
160
172
|
doc[gate.key.to_s]
|
161
173
|
when :set
|
162
174
|
fields_to_gate_value fields, gate
|
175
|
+
when :json
|
176
|
+
value = doc[gate.key.to_s]
|
177
|
+
Typecast.from_json(value)
|
163
178
|
else
|
164
179
|
unsupported_data_type gate.data_type
|
165
180
|
end
|
@@ -8,28 +8,19 @@ module Flipper
|
|
8
8
|
class RedisCache
|
9
9
|
include ::Flipper::Adapter
|
10
10
|
|
11
|
-
Version = 'v1'.freeze
|
12
|
-
Namespace = "flipper/#{Version}".freeze
|
13
|
-
FeaturesKey = "#{Namespace}/features".freeze
|
14
|
-
GetAllKey = "#{Namespace}/get_all".freeze
|
15
|
-
|
16
|
-
# Private
|
17
|
-
def self.key_for(key)
|
18
|
-
"#{Namespace}/feature/#{key}"
|
19
|
-
end
|
20
|
-
|
21
11
|
# Internal
|
22
12
|
attr_reader :cache
|
23
13
|
|
24
|
-
# Public: The name of the adapter.
|
25
|
-
attr_reader :name
|
26
|
-
|
27
14
|
# Public
|
28
15
|
def initialize(adapter, cache, ttl = 3600)
|
29
16
|
@adapter = adapter
|
30
|
-
@name = :redis_cache
|
31
17
|
@cache = cache
|
32
18
|
@ttl = ttl
|
19
|
+
|
20
|
+
@version = 'v1'.freeze
|
21
|
+
@namespace = "flipper/#{@version}".freeze
|
22
|
+
@features_key = "#{@namespace}/features".freeze
|
23
|
+
@get_all_key = "#{@namespace}/get_all".freeze
|
33
24
|
end
|
34
25
|
|
35
26
|
# Public
|
@@ -40,14 +31,14 @@ module Flipper
|
|
40
31
|
# Public
|
41
32
|
def add(feature)
|
42
33
|
result = @adapter.add(feature)
|
43
|
-
@cache.del(
|
34
|
+
@cache.del(@features_key)
|
44
35
|
result
|
45
36
|
end
|
46
37
|
|
47
38
|
# Public
|
48
39
|
def remove(feature)
|
49
40
|
result = @adapter.remove(feature)
|
50
|
-
@cache.del(
|
41
|
+
@cache.del(@features_key)
|
51
42
|
@cache.del(key_for(feature.key))
|
52
43
|
result
|
53
44
|
end
|
@@ -71,13 +62,13 @@ module Flipper
|
|
71
62
|
end
|
72
63
|
|
73
64
|
def get_all
|
74
|
-
if @cache.setnx(
|
75
|
-
@cache.expire(
|
65
|
+
if @cache.setnx(@get_all_key, Time.now.to_i)
|
66
|
+
@cache.expire(@get_all_key, @ttl)
|
76
67
|
response = @adapter.get_all
|
77
68
|
response.each do |key, value|
|
78
69
|
set_with_ttl key_for(key), value
|
79
70
|
end
|
80
|
-
set_with_ttl
|
71
|
+
set_with_ttl @features_key, response.keys.to_set
|
81
72
|
response
|
82
73
|
else
|
83
74
|
features = read_feature_keys.map { |key| Flipper::Feature.new(key, self) }
|
@@ -102,11 +93,11 @@ module Flipper
|
|
102
93
|
private
|
103
94
|
|
104
95
|
def key_for(key)
|
105
|
-
|
96
|
+
"#{@namespace}/feature/#{key}"
|
106
97
|
end
|
107
98
|
|
108
99
|
def read_feature_keys
|
109
|
-
fetch(
|
100
|
+
fetch(@features_key) { @adapter.features }
|
110
101
|
end
|
111
102
|
|
112
103
|
def read_many_features(features)
|
data/lib/flipper/version.rb
CHANGED
@@ -1,3 +1,13 @@
|
|
1
1
|
module Flipper
|
2
|
-
VERSION = '
|
2
|
+
VERSION = '1.2.2'.freeze
|
3
|
+
|
4
|
+
REQUIRED_RUBY_VERSION = '2.6'.freeze
|
5
|
+
NEXT_REQUIRED_RUBY_VERSION = '3.0'.freeze
|
6
|
+
|
7
|
+
REQUIRED_RAILS_VERSION = '5.2'.freeze
|
8
|
+
NEXT_REQUIRED_RAILS_VERSION = '6.1.0'.freeze
|
9
|
+
|
10
|
+
def self.deprecated_ruby_version?
|
11
|
+
Gem::Version.new(RUBY_VERSION) < Gem::Version.new(NEXT_REQUIRED_RUBY_VERSION)
|
12
|
+
end
|
3
13
|
end
|
@@ -17,10 +17,8 @@ RSpec.describe Flipper::Adapters::RedisCache do
|
|
17
17
|
subject { adapter }
|
18
18
|
|
19
19
|
before do
|
20
|
-
|
20
|
+
skip_on_error(Redis::CannotConnectError, 'Redis not available') do
|
21
21
|
client.flushdb
|
22
|
-
rescue Redis::CannotConnectError
|
23
|
-
ENV['CI'] ? raise : skip('Redis not available')
|
24
22
|
end
|
25
23
|
end
|
26
24
|
|
@@ -31,7 +29,7 @@ RSpec.describe Flipper::Adapters::RedisCache do
|
|
31
29
|
feature = flipper[:stats]
|
32
30
|
adapter.get(feature)
|
33
31
|
adapter.remove(feature)
|
34
|
-
expect(client.get(
|
32
|
+
expect(client.get("flipper/v1/feature/#{feature.key}")).to be(nil)
|
35
33
|
end
|
36
34
|
end
|
37
35
|
|
@@ -39,7 +37,7 @@ RSpec.describe Flipper::Adapters::RedisCache do
|
|
39
37
|
it 'uses correct cache key' do
|
40
38
|
stats = flipper[:stats]
|
41
39
|
adapter.get(stats)
|
42
|
-
expect(client.get(
|
40
|
+
expect(client.get("flipper/v1/feature/#{stats.key}")).not_to be_nil
|
43
41
|
end
|
44
42
|
end
|
45
43
|
|
@@ -54,13 +52,13 @@ RSpec.describe Flipper::Adapters::RedisCache do
|
|
54
52
|
memory_adapter.reset
|
55
53
|
|
56
54
|
adapter.get(stats)
|
57
|
-
expect(client.get(
|
58
|
-
expect(client.get(
|
55
|
+
expect(client.get("flipper/v1/feature/#{search.key}")).to be(nil)
|
56
|
+
expect(client.get("flipper/v1/feature/#{other.key}")).to be(nil)
|
59
57
|
|
60
58
|
adapter.get_multi([stats, search, other])
|
61
59
|
|
62
60
|
search_cache_value, other_cache_value = [search, other].map do |f|
|
63
|
-
Marshal.load(client.get(
|
61
|
+
Marshal.load(client.get("flipper/v1/feature/#{f.key}"))
|
64
62
|
end
|
65
63
|
expect(search_cache_value[:boolean]).to eq('true')
|
66
64
|
expect(other_cache_value[:boolean]).to be(nil)
|
@@ -82,9 +80,9 @@ RSpec.describe Flipper::Adapters::RedisCache do
|
|
82
80
|
|
83
81
|
it 'warms all features' do
|
84
82
|
adapter.get_all
|
85
|
-
expect(Marshal.load(client.get(
|
86
|
-
expect(Marshal.load(client.get(
|
87
|
-
expect(client.get(
|
83
|
+
expect(Marshal.load(client.get("flipper/v1/feature/#{stats.key}"))[:boolean]).to eq('true')
|
84
|
+
expect(Marshal.load(client.get("flipper/v1/feature/#{search.key}"))[:boolean]).to be(nil)
|
85
|
+
expect(client.get("flipper/v1/get_all").to_i).to be_within(2).of(Time.now.to_i)
|
88
86
|
end
|
89
87
|
|
90
88
|
it 'returns same result when already cached' do
|
@@ -13,10 +13,8 @@ RSpec.describe Flipper::Adapters::Redis do
|
|
13
13
|
subject { described_class.new(client) }
|
14
14
|
|
15
15
|
before do
|
16
|
-
|
16
|
+
skip_on_error(Redis::CannotConnectError, 'Redis not available') do
|
17
17
|
client.flushdb
|
18
|
-
rescue Redis::CannotConnectError
|
19
|
-
ENV['CI'] ? raise : skip('Redis not available')
|
20
18
|
end
|
21
19
|
end
|
22
20
|
|
@@ -30,4 +28,28 @@ RSpec.describe Flipper::Adapters::Redis do
|
|
30
28
|
|
31
29
|
expect(Flipper.adapter.adapter).to be_a(Flipper::Adapters::Redis)
|
32
30
|
end
|
31
|
+
|
32
|
+
describe 'with a key_prefix' do
|
33
|
+
let(:subject) { described_class.new(client, key_prefix: "lockbox:") }
|
34
|
+
let(:feature) { Flipper::Feature.new(:search, subject) }
|
35
|
+
|
36
|
+
it_should_behave_like 'a flipper adapter'
|
37
|
+
|
38
|
+
it 'namespaces feature-keys' do
|
39
|
+
subject.add(feature)
|
40
|
+
|
41
|
+
expect(client.smembers("flipper_features")).to eq([])
|
42
|
+
expect(client.exists?("search")).to eq(false)
|
43
|
+
expect(client.smembers("lockbox:flipper_features")).to eq(["search"])
|
44
|
+
expect(client.hgetall("lockbox:search")).not_to eq(nil)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "can remove namespaced keys" do
|
48
|
+
subject.add(feature)
|
49
|
+
expect(client.smembers("lockbox:flipper_features")).to eq(["search"])
|
50
|
+
|
51
|
+
subject.remove(feature)
|
52
|
+
expect(client.smembers("lockbox:flipper_features")).to be_empty
|
53
|
+
end
|
54
|
+
end
|
33
55
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flipper-redis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Nunemaker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-19 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:
|
19
|
+
version: 1.2.2
|
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:
|
26
|
+
version: 1.2.2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: redis
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -45,8 +45,7 @@ dependencies:
|
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '6'
|
47
47
|
description:
|
48
|
-
email:
|
49
|
-
- nunemaker@gmail.com
|
48
|
+
email: support@flippercloud.io
|
50
49
|
executables: []
|
51
50
|
extensions: []
|
52
51
|
extra_rdoc_files: []
|
@@ -63,11 +62,15 @@ files:
|
|
63
62
|
- spec/flipper/adapters/redis_spec.rb
|
64
63
|
- test/adapters/redis_cache_test.rb
|
65
64
|
- test/adapters/redis_test.rb
|
66
|
-
homepage: https://
|
65
|
+
homepage: https://www.flippercloud.io/docs/adapters/redis
|
67
66
|
licenses:
|
68
67
|
- MIT
|
69
68
|
metadata:
|
70
|
-
|
69
|
+
documentation_uri: https://www.flippercloud.io/docs
|
70
|
+
homepage_uri: https://www.flippercloud.io
|
71
|
+
source_code_uri: https://github.com/flippercloud/flipper
|
72
|
+
bug_tracker_uri: https://github.com/flippercloud/flipper/issues
|
73
|
+
changelog_uri: https://github.com/flippercloud/flipper/releases/tag/v1.2.2
|
71
74
|
post_install_message:
|
72
75
|
rdoc_options: []
|
73
76
|
require_paths:
|
@@ -83,10 +86,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
86
|
- !ruby/object:Gem::Version
|
84
87
|
version: '0'
|
85
88
|
requirements: []
|
86
|
-
rubygems_version: 3.3
|
89
|
+
rubygems_version: 3.5.3
|
87
90
|
signing_key:
|
88
91
|
specification_version: 4
|
89
|
-
summary: Redis adapter for Flipper
|
92
|
+
summary: Redis feature flag adapter for Flipper
|
90
93
|
test_files:
|
91
94
|
- spec/flipper/adapters/redis_cache_spec.rb
|
92
95
|
- spec/flipper/adapters/redis_spec.rb
|