splitclient-rb 8.2.0-java → 8.3.0.pre.rc2-java
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/splitclient-rb/cache/fetchers/split_fetcher.rb +2 -29
- data/lib/splitclient-rb/cache/filter/flag_set_filter.rb +40 -0
- data/lib/splitclient-rb/cache/repositories/flag_sets/memory_repository.rb +40 -0
- data/lib/splitclient-rb/cache/repositories/flag_sets/redis_repository.rb +49 -0
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +100 -39
- data/lib/splitclient-rb/cache/stores/localhost_split_store.rb +1 -1
- data/lib/splitclient-rb/clients/split_client.rb +165 -81
- data/lib/splitclient-rb/engine/api/splits.rb +9 -3
- data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +1 -1
- data/lib/splitclient-rb/engine/parser/evaluator.rb +15 -21
- data/lib/splitclient-rb/exceptions.rb +11 -0
- data/lib/splitclient-rb/helpers/repository_helper.rb +23 -0
- data/lib/splitclient-rb/split_config.rb +22 -6
- data/lib/splitclient-rb/split_factory.rb +32 -9
- data/lib/splitclient-rb/sse/workers/splits_worker.rb +2 -9
- data/lib/splitclient-rb/telemetry/domain/constants.rb +4 -0
- data/lib/splitclient-rb/telemetry/domain/structs.rb +4 -4
- data/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb +18 -2
- data/lib/splitclient-rb/telemetry/redis/redis_synchronizer.rb +0 -1
- data/lib/splitclient-rb/telemetry/storages/memory.rb +12 -0
- data/lib/splitclient-rb/telemetry/synchronizer.rb +6 -2
- data/lib/splitclient-rb/validators.rb +63 -3
- data/lib/splitclient-rb/version.rb +1 -1
- data/lib/splitclient-rb.rb +4 -0
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d4d51065bea1f95afa628a82a475e6f9ba405c2
|
4
|
+
data.tar.gz: 724f28c892996270ec1ed3f60f33b39620389f31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c791f77af6bc85f0893428077e7bbf48cd462bea313389e34262741d1f9c53e316bffb1173e01b0e4de7bc81663e55ae41e4759ca66c3376b3372393ed82f11b
|
7
|
+
data.tar.gz: c876c0cc8b1ab4ed26233b2dbb0547dd8857b53ce0b2ac827572255d795e7d3087305a3f40ab5ec0fecbc1a98a0eb248647441bb273c9d624f3d0eb509345ca2
|
@@ -17,7 +17,7 @@ module SplitIoClient
|
|
17
17
|
fetch_splits
|
18
18
|
return
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
splits_thread
|
22
22
|
end
|
23
23
|
|
@@ -25,13 +25,8 @@ module SplitIoClient
|
|
25
25
|
@semaphore.synchronize do
|
26
26
|
data = splits_since(@splits_repository.get_change_number, fetch_options)
|
27
27
|
|
28
|
-
data[:splits]
|
29
|
-
add_split_unless_archived(split)
|
30
|
-
end
|
31
|
-
|
28
|
+
SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(@splits_repository, data[:splits], data[:till], @config)
|
32
29
|
@splits_repository.set_segment_names(data[:segment_names])
|
33
|
-
@splits_repository.set_change_number(data[:till])
|
34
|
-
|
35
30
|
@config.logger.debug("segments seen(#{data[:segment_names].length}): #{data[:segment_names].to_a}") if @config.debug_enabled
|
36
31
|
|
37
32
|
{ segment_names: data[:segment_names], success: true }
|
@@ -64,28 +59,6 @@ module SplitIoClient
|
|
64
59
|
splits_api.since(since, fetch_options)
|
65
60
|
end
|
66
61
|
|
67
|
-
def add_split_unless_archived(split)
|
68
|
-
if Engine::Models::Split.archived?(split)
|
69
|
-
@config.logger.debug("Seeing archived feature flag #{split[:name]}") if @config.debug_enabled
|
70
|
-
|
71
|
-
remove_archived_split(split)
|
72
|
-
else
|
73
|
-
store_split(split)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def remove_archived_split(split)
|
78
|
-
@config.logger.debug("removing feature flag from store(#{split})") if @config.debug_enabled
|
79
|
-
|
80
|
-
@splits_repository.remove_split(split)
|
81
|
-
end
|
82
|
-
|
83
|
-
def store_split(split)
|
84
|
-
@config.logger.debug("storing feature flag (#{split[:name]})") if @config.debug_enabled
|
85
|
-
|
86
|
-
@splits_repository.add_split(split)
|
87
|
-
end
|
88
|
-
|
89
62
|
def splits_api
|
90
63
|
@splits_api ||= SplitIoClient::Api::Splits.new(@api_key, @config, @telemetry_runtime_producer)
|
91
64
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module SplitIoClient
|
6
|
+
module Cache
|
7
|
+
module Filter
|
8
|
+
class FlagSetsFilter
|
9
|
+
def initialize(flag_sets = [])
|
10
|
+
@flag_sets = Set.new(flag_sets)
|
11
|
+
@should_filter = @flag_sets.any?
|
12
|
+
end
|
13
|
+
|
14
|
+
def should_filter?
|
15
|
+
@should_filter
|
16
|
+
end
|
17
|
+
|
18
|
+
def flag_set_exist?(flag_set)
|
19
|
+
return true unless @should_filter
|
20
|
+
|
21
|
+
if not flag_set.is_a?(String) or flag_set.empty?
|
22
|
+
return false
|
23
|
+
end
|
24
|
+
|
25
|
+
@flag_sets.intersection([flag_set]).any?
|
26
|
+
end
|
27
|
+
|
28
|
+
def intersect?(flag_sets)
|
29
|
+
return true unless @should_filter
|
30
|
+
|
31
|
+
if not flag_sets.is_a?(Array) or flag_sets.empty?
|
32
|
+
return false
|
33
|
+
end
|
34
|
+
|
35
|
+
@flag_sets.intersection(Set.new(flag_sets)).any?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'concurrent'
|
2
|
+
|
3
|
+
module SplitIoClient
|
4
|
+
module Cache
|
5
|
+
module Repositories
|
6
|
+
class MemoryFlagSetsRepository
|
7
|
+
def initialize(flag_sets = [])
|
8
|
+
@sets_feature_flag_map = {}
|
9
|
+
flag_sets.each{ |flag_set| @sets_feature_flag_map[flag_set] = Set[] }
|
10
|
+
end
|
11
|
+
|
12
|
+
def flag_set_exist?(flag_set)
|
13
|
+
@sets_feature_flag_map.key?(flag_set)
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_flag_sets(flag_sets)
|
17
|
+
to_return = Array.new
|
18
|
+
flag_sets.each { |flag_set| to_return.concat(@sets_feature_flag_map[flag_set].to_a)}
|
19
|
+
to_return.uniq
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_flag_set(flag_set)
|
23
|
+
@sets_feature_flag_map[flag_set] = Set[] if !flag_set_exist?(flag_set)
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove_flag_set(flag_set)
|
27
|
+
@sets_feature_flag_map.delete(flag_set) if flag_set_exist?(flag_set)
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_feature_flag_to_flag_set(flag_set, feature_flag)
|
31
|
+
@sets_feature_flag_map[flag_set].add(feature_flag) if flag_set_exist?(flag_set)
|
32
|
+
end
|
33
|
+
|
34
|
+
def remove_feature_flag_from_flag_set(flag_set, feature_flag)
|
35
|
+
@sets_feature_flag_map[flag_set].delete(feature_flag) if flag_set_exist?(flag_set)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'concurrent'
|
2
|
+
|
3
|
+
module SplitIoClient
|
4
|
+
module Cache
|
5
|
+
module Repositories
|
6
|
+
class RedisFlagSetsRepository < Repository
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
super(config)
|
10
|
+
@adapter = SplitIoClient::Cache::Adapters::RedisAdapter.new(@config.redis_url)
|
11
|
+
end
|
12
|
+
|
13
|
+
def flag_set_exist?(flag_set)
|
14
|
+
@adapter.exists?(namespace_key(".flagSet.#{flag_set}"))
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_flag_sets(flag_sets)
|
18
|
+
result = @adapter.redis.pipelined do |pipeline|
|
19
|
+
flag_sets.each do |flag_set|
|
20
|
+
pipeline.smembers(namespace_key(".flagSet.#{flag_set}"))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
to_return = Array.new
|
24
|
+
result.each do |flag_set|
|
25
|
+
flag_set.each { |feature_flag_name| to_return.push(feature_flag_name.to_s)}
|
26
|
+
end
|
27
|
+
to_return.uniq
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_flag_set(flag_set)
|
31
|
+
# not implemented
|
32
|
+
end
|
33
|
+
|
34
|
+
def remove_flag_set(flag_set)
|
35
|
+
# not implemented
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_feature_flag_to_flag_set(flag_set, feature_flag)
|
39
|
+
# not implemented
|
40
|
+
end
|
41
|
+
|
42
|
+
def remove_feature_flag_from_flag_set(flag_set, feature_flag)
|
43
|
+
# not implemented
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -6,7 +6,7 @@ module SplitIoClient
|
|
6
6
|
class SplitsRepository < Repository
|
7
7
|
attr_reader :adapter
|
8
8
|
|
9
|
-
def initialize(config)
|
9
|
+
def initialize(config, flag_sets_repository, flag_set_filter)
|
10
10
|
super(config)
|
11
11
|
@tt_cache = {}
|
12
12
|
@adapter = case @config.cache_adapter.class.to_s
|
@@ -15,48 +15,18 @@ module SplitIoClient
|
|
15
15
|
else
|
16
16
|
@config.cache_adapter
|
17
17
|
end
|
18
|
+
@flag_sets = flag_sets_repository
|
19
|
+
@flag_set_filter = flag_set_filter
|
18
20
|
unless @config.mode.equal?(:consumer)
|
19
21
|
@adapter.set_string(namespace_key('.splits.till'), '-1')
|
20
22
|
@adapter.initialize_map(namespace_key('.segments.registered'))
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
if(!existing_split)
|
29
|
-
increase_tt_name_count(split[:trafficTypeName])
|
30
|
-
elsif(existing_split[:trafficTypeName] != split[:trafficTypeName])
|
31
|
-
increase_tt_name_count(split[:trafficTypeName])
|
32
|
-
decrease_tt_name_count(existing_split[:trafficTypeName])
|
33
|
-
end
|
34
|
-
|
35
|
-
@adapter.set_string(namespace_key(".split.#{split[:name]}"), split.to_json)
|
36
|
-
end
|
37
|
-
|
38
|
-
def remove_split(split)
|
39
|
-
tt_name = split[:trafficTypeName]
|
40
|
-
|
41
|
-
decrease_tt_name_count(split[:trafficTypeName])
|
42
|
-
|
43
|
-
@adapter.delete(namespace_key(".split.#{split[:name]}"))
|
44
|
-
end
|
45
|
-
|
46
|
-
def get_splits(names, symbolize_names = true)
|
47
|
-
splits = {}
|
48
|
-
split_names = names.map { |name| namespace_key(".split.#{name}") }
|
49
|
-
splits.merge!(
|
50
|
-
@adapter
|
51
|
-
.multiple_strings(split_names)
|
52
|
-
.map { |name, data| [name.gsub(namespace_key('.split.'), ''), data] }.to_h
|
53
|
-
)
|
54
|
-
|
55
|
-
splits.map do |name, data|
|
56
|
-
parsed_data = data ? JSON.parse(data, symbolize_names: true) : nil
|
57
|
-
split_name = symbolize_names ? name.to_sym : name
|
58
|
-
[split_name, parsed_data]
|
59
|
-
end.to_h
|
26
|
+
def update(to_add, to_delete, new_change_number)
|
27
|
+
to_add.each{ |feature_flag| add_feature_flag(feature_flag) }
|
28
|
+
to_delete.each{ |feature_flag| remove_feature_flag(feature_flag) }
|
29
|
+
set_change_number(new_change_number)
|
60
30
|
end
|
61
31
|
|
62
32
|
def get_split(name)
|
@@ -65,8 +35,13 @@ module SplitIoClient
|
|
65
35
|
JSON.parse(split, symbolize_names: true) if split
|
66
36
|
end
|
67
37
|
|
68
|
-
def splits
|
69
|
-
|
38
|
+
def splits(filtered_names=nil)
|
39
|
+
symbolize = true
|
40
|
+
if filtered_names.nil?
|
41
|
+
filtered_names = split_names
|
42
|
+
symbolize = false
|
43
|
+
end
|
44
|
+
get_splits(filtered_names, symbolize)
|
70
45
|
end
|
71
46
|
|
72
47
|
def traffic_type_exists(tt_name)
|
@@ -144,8 +119,94 @@ module SplitIoClient
|
|
144
119
|
split_names.length
|
145
120
|
end
|
146
121
|
|
122
|
+
def get_feature_flags_by_sets(flag_sets)
|
123
|
+
sets_to_fetch = Array.new
|
124
|
+
flag_sets.each do |flag_set|
|
125
|
+
unless @flag_sets.flag_set_exist?(flag_set)
|
126
|
+
@config.logger.warn("Flag set #{flag_set} is not part of the configured flag set list, ignoring it.")
|
127
|
+
next
|
128
|
+
end
|
129
|
+
sets_to_fetch.push(flag_set)
|
130
|
+
end
|
131
|
+
@flag_sets.get_flag_sets(flag_sets)
|
132
|
+
end
|
133
|
+
|
134
|
+
def is_flag_set_exist(flag_set)
|
135
|
+
@flag_sets.flag_set_exist?(flag_set)
|
136
|
+
end
|
137
|
+
|
138
|
+
def flag_set_filter
|
139
|
+
@flag_set_filter
|
140
|
+
end
|
141
|
+
|
147
142
|
private
|
148
143
|
|
144
|
+
def add_feature_flag(split)
|
145
|
+
return unless split[:name]
|
146
|
+
existing_split = get_split(split[:name])
|
147
|
+
|
148
|
+
if(!existing_split)
|
149
|
+
increase_tt_name_count(split[:trafficTypeName])
|
150
|
+
elsif(existing_split[:trafficTypeName] != split[:trafficTypeName])
|
151
|
+
increase_tt_name_count(split[:trafficTypeName])
|
152
|
+
decrease_tt_name_count(existing_split[:trafficTypeName])
|
153
|
+
remove_from_flag_sets(existing_split)
|
154
|
+
elsif(existing_split[:sets] != split[:sets])
|
155
|
+
remove_from_flag_sets(existing_split)
|
156
|
+
end
|
157
|
+
|
158
|
+
if !split[:sets].nil?
|
159
|
+
for flag_set in split[:sets]
|
160
|
+
if !@flag_sets.flag_set_exist?(flag_set)
|
161
|
+
if @flag_set_filter.should_filter?
|
162
|
+
next
|
163
|
+
end
|
164
|
+
@flag_sets.add_flag_set(flag_set)
|
165
|
+
end
|
166
|
+
@flag_sets.add_feature_flag_to_flag_set(flag_set, split[:name])
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
@adapter.set_string(namespace_key(".split.#{split[:name]}"), split.to_json)
|
171
|
+
end
|
172
|
+
|
173
|
+
def remove_feature_flag(split)
|
174
|
+
tt_name = split[:trafficTypeName]
|
175
|
+
|
176
|
+
decrease_tt_name_count(split[:trafficTypeName])
|
177
|
+
remove_from_flag_sets(split)
|
178
|
+
@adapter.delete(namespace_key(".split.#{split[:name]}"))
|
179
|
+
end
|
180
|
+
|
181
|
+
def get_splits(names, symbolize_names = true)
|
182
|
+
splits = {}
|
183
|
+
split_names = names.map { |name| namespace_key(".split.#{name}") }
|
184
|
+
splits.merge!(
|
185
|
+
@adapter
|
186
|
+
.multiple_strings(split_names)
|
187
|
+
.map { |name, data| [name.gsub(namespace_key('.split.'), ''), data] }.to_h
|
188
|
+
)
|
189
|
+
|
190
|
+
splits.map do |name, data|
|
191
|
+
parsed_data = data ? JSON.parse(data, symbolize_names: true) : nil
|
192
|
+
split_name = symbolize_names ? name.to_sym : name
|
193
|
+
[split_name, parsed_data]
|
194
|
+
end.to_h
|
195
|
+
end
|
196
|
+
|
197
|
+
def remove_from_flag_sets(feature_flag)
|
198
|
+
name = feature_flag[:name]
|
199
|
+
flag_sets = get_split(name)[:sets] if exists?(name)
|
200
|
+
if !flag_sets.nil?
|
201
|
+
for flag_set in flag_sets
|
202
|
+
@flag_sets.remove_feature_flag_from_flag_set(flag_set, feature_flag[:name])
|
203
|
+
if is_flag_set_exist(flag_set) && @flag_sets.get_flag_sets([flag_set]).length == 0 && !@flag_set_filter.should_filter?
|
204
|
+
@flag_sets.remove_flag_set(flag_set)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
149
210
|
def increase_tt_name_count(tt_name)
|
150
211
|
return unless tt_name
|
151
212
|
|