Skip to content

Commit b72babe

Browse files
authored
Merge pull request #549 from splitio/rbs-fetcher
Added RBS support for fetcher
2 parents 09829cf + 8a9defb commit b72babe

File tree

11 files changed

+179
-80
lines changed

11 files changed

+179
-80
lines changed

lib/splitclient-rb/cache/fetchers/split_fetcher.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ module SplitIoClient
22
module Cache
33
module Fetchers
44
class SplitFetcher
5-
attr_reader :splits_repository
5+
attr_reader :splits_repository, :rule_based_segments_repository
66

7-
def initialize(splits_repository, api_key, config, telemetry_runtime_producer)
7+
def initialize(splits_repository, rule_based_segments_repository, api_key, config, telemetry_runtime_producer)
88
@splits_repository = splits_repository
9+
@rule_based_segments_repository = rule_based_segments_repository
910
@api_key = api_key
1011
@config = config
1112
@semaphore = Mutex.new
@@ -23,9 +24,10 @@ def call
2324

2425
def fetch_splits(fetch_options = { cache_control_headers: false, till: nil })
2526
@semaphore.synchronize do
26-
data = splits_since(@splits_repository.get_change_number, fetch_options)
27+
data = splits_since(@splits_repository.get_change_number, @rule_based_segments_repository.get_change_number, fetch_options)
2728

28-
SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(@splits_repository, data[:splits], data[:till], @config)
29+
SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(@splits_repository, data[:ff][:d], data[:ff][:t], @config)
30+
SplitIoClient::Helpers::RepositoryHelper.update_rule_based_segment_repository(@rule_based_segments_repository, data[:rbs][:d], data[:rbs][:t], @config)
2931
@splits_repository.set_segment_names(data[:segment_names])
3032
@config.logger.debug("segments seen(#{data[:segment_names].length}): #{data[:segment_names].to_a}") if @config.debug_enabled
3133

@@ -55,8 +57,8 @@ def splits_thread
5557
end
5658
end
5759

58-
def splits_since(since, fetch_options = { cache_control_headers: false, till: nil })
59-
splits_api.since(since, fetch_options)
60+
def splits_since(since, since_rbs, fetch_options = { cache_control_headers: false, till: nil })
61+
splits_api.since(since, since_rbs, fetch_options)
6062
end
6163

6264
def splits_api

lib/splitclient-rb/engine/api/splits.rb

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ def initialize(api_key, config, telemetry_runtime_producer)
1212
@flag_sets_filter = @config.flag_sets_filter
1313
end
1414

15-
def since(since, fetch_options = { cache_control_headers: false, till: nil, sets: nil})
15+
def since(since, since_rbs, fetch_options = { cache_control_headers: false, till: nil, sets: nil})
1616
start = Time.now
1717

18-
params = { s: SplitIoClient::Spec::FeatureFlags::SPEC_VERSION, since: since }
18+
params = { s: SplitIoClient::Spec::FeatureFlags::SPEC_VERSION, since: since, rbSince: since_rbs }
1919
params[:sets] = @flag_sets_filter.join(",") unless @flag_sets_filter.empty?
2020
params[:till] = fetch_options[:till] unless fetch_options[:till].nil?
2121
@config.logger.debug("Fetching from splitChanges with #{params}: ")
@@ -25,11 +25,17 @@ def since(since, fetch_options = { cache_control_headers: false, till: nil, sets
2525
raise ApiException.new response.body, 414
2626
end
2727
if response.success?
28-
result = splits_with_segment_names(response.body)
29-
unless result[:splits].empty?
30-
@config.split_logger.log_if_debug("#{result[:splits].length} feature flags retrieved. since=#{since}")
28+
result = objects_with_segment_names(response.body)
29+
30+
unless result[:ff][:d].empty?
31+
@config.split_logger.log_if_debug("#{result[:ff][:d].length} feature flags retrieved. since=#{since}")
3132
end
32-
@config.split_logger.log_if_transport("Feature flag changes response: #{result.to_s}")
33+
@config.split_logger.log_if_transport("Feature flag changes response: #{result[:ff].to_s}")
34+
35+
unless result[:rbs][:d].empty?
36+
@config.split_logger.log_if_debug("#{result[:ff][:d].length} rule based segments retrieved. since=#{since_rbs}")
37+
end
38+
@config.split_logger.log_if_transport("rule based segments changes response: #{result[:rbs].to_s}")
3339

3440
bucket = BinarySearchLatencyTracker.get_bucket((Time.now - start) * 1000.0)
3541
@telemetry_runtime_producer.record_sync_latency(Telemetry::Domain::Constants::SPLIT_SYNC, bucket)
@@ -48,15 +54,19 @@ def since(since, fetch_options = { cache_control_headers: false, till: nil, sets
4854

4955
private
5056

51-
def splits_with_segment_names(splits_json)
52-
parsed_splits = JSON.parse(splits_json, symbolize_names: true)
57+
def objects_with_segment_names(objects_json)
58+
parsed_objects = JSON.parse(objects_json, symbolize_names: true)
5359

54-
parsed_splits[:segment_names] =
55-
parsed_splits[:splits].each_with_object(Set.new) do |split, splits|
56-
splits << Helpers::Util.segment_names_by_feature_flag(split)
60+
parsed_objects[:segment_names] =
61+
parsed_objects[:ff][:d].each_with_object(Set.new) do |split, splits|
62+
splits << Helpers::Util.segment_names_by_object(split)
5763
end.flatten
58-
59-
parsed_splits
64+
if not parsed_objects[:ff][:rbs].nil?
65+
parsed_objects[:segment_names].merge parsed_objects[:ff][:rbs].each_with_object(Set.new) do |rule_based_segment, rule_based_segments|
66+
rule_based_segments << Helpers::Util.segment_names_by_object(rule_based_segment)
67+
end.flatten
68+
end
69+
parsed_objects
6070
end
6171
end
6272
end

lib/splitclient-rb/helpers/repository_helper.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,22 @@ def self.update_feature_flag_repository(feature_flag_repository, feature_flags,
2525
end
2626
feature_flag_repository.update(to_add, to_delete, change_number)
2727
end
28+
29+
def self.update_rule_based_segment_repository(rule_based_segment_repository, rule_based_segments, change_number, config)
30+
to_add = []
31+
to_delete = []
32+
rule_based_segments.each do |rule_based_segment|
33+
if Engine::Models::Split.archived?(rule_based_segment)
34+
config.logger.debug("removing rule based segment from store(#{rule_based_segment})") if config.debug_enabled
35+
to_delete.push(rule_based_segment)
36+
next
37+
end
38+
39+
config.logger.debug("storing rule based segment (#{rule_based_segment[:name]})") if config.debug_enabled
40+
to_add.push(rule_based_segment)
41+
end
42+
rule_based_segment_repository.update(to_add, to_delete, change_number)
43+
end
2844
end
2945
end
3046
end

lib/splitclient-rb/helpers/util.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
module SplitIoClient
44
module Helpers
55
class Util
6-
def self.segment_names_by_feature_flag(feature_flag)
7-
feature_flag[:conditions].each_with_object(Set.new) do |condition, names|
6+
def self.segment_names_by_object(object)
7+
object[:conditions].each_with_object(Set.new) do |condition, names|
88
condition[:matcherGroup][:matchers].each do |matcher|
99
next if matcher[:userDefinedSegmentMatcherData].nil?
1010

lib/splitclient-rb/spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module SplitIoClient
44
module Spec
55
class FeatureFlags
6-
SPEC_VERSION = "1.1"
6+
SPEC_VERSION = "1.3"
77
end
88
end
99
end

spec/cache/fetchers/segment_fetch_spec.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,11 @@
3636
let(:flag_sets_repository) {SplitIoClient::Cache::Repositories::MemoryFlagSetsRepository.new([]) }
3737
let(:flag_set_filter) {SplitIoClient::Cache::Filter::FlagSetsFilter.new([]) }
3838
let(:splits_repository) { SplitIoClient::Cache::Repositories::SplitsRepository.new(config, flag_sets_repository, flag_set_filter) }
39+
let(:rule_based_segments_repository) { SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository.new(config) }
3940
let(:telemetry_runtime_producer) { SplitIoClient::Telemetry::RuntimeProducer.new(config) }
4041
let(:segment_fetcher) { described_class.new(segments_repository, '', config, telemetry_runtime_producer) }
4142
let(:split_fetcher) do
42-
SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, '', config, telemetry_runtime_producer)
43+
SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, rule_based_segments_repository, '', config, telemetry_runtime_producer)
4344
end
4445

4546
it 'fetch segments' do
@@ -72,10 +73,11 @@
7273
let(:flag_sets_repository) {SplitIoClient::Cache::Repositories::RedisFlagSetsRepository.new(config) }
7374
let(:flag_set_filter) {SplitIoClient::Cache::Filter::FlagSetsFilter.new([]) }
7475
let(:splits_repository) { SplitIoClient::Cache::Repositories::SplitsRepository.new(config, flag_sets_repository, flag_set_filter) }
76+
let(:rule_based_segments_repository) { SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository.new(config) }
7577
let(:telemetry_runtime_producer) { SplitIoClient::Telemetry::RuntimeProducer.new(config) }
7678
let(:segment_fetcher) { described_class.new(segments_repository, '', config, telemetry_runtime_producer) }
7779
let(:split_fetcher) do
78-
SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, '', config, telemetry_runtime_producer)
80+
SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, rule_based_segments_repository, '', config, telemetry_runtime_producer)
7981
end
8082

8183
it 'fetch segments' do

spec/cache/fetchers/split_fetch_spec.rb

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
end
1212

1313
before do
14-
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')
14+
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1')
1515
.to_return(status: 200, body: active_splits_json)
1616
end
1717

@@ -26,20 +26,23 @@
2626
let(:flag_sets_repository) {SplitIoClient::Cache::Repositories::MemoryFlagSetsRepository.new([]) }
2727
let(:flag_set_filter) {SplitIoClient::Cache::Filter::FlagSetsFilter.new([]) }
2828
let(:splits_repository) { SplitIoClient::Cache::Repositories::SplitsRepository.new(config, flag_sets_repository, flag_set_filter) }
29+
let(:rule_based_segments_repository) { SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository.new(config) }
2930
let(:telemetry_runtime_producer) { SplitIoClient::Telemetry::RuntimeProducer.new(config) }
30-
let(:store) { described_class.new(splits_repository, '', config, telemetry_runtime_producer) }
31+
let(:store) { described_class.new(splits_repository, rule_based_segments_repository, '', config, telemetry_runtime_producer) }
3132

3233
it 'returns splits since' do
33-
splits = store.send(:splits_since, -1)
34+
splits = store.send(:splits_since, -1, -1)
3435

35-
expect(splits[:splits].count).to eq(2)
36+
expect(splits[:ff][:d].count).to eq(2)
37+
expect(splits[:rbs][:d].count).to eq(1)
3638
end
3739

3840
it 'fetch data in the cache' do
3941
store.send(:fetch_splits)
40-
4142
expect(store.splits_repository.splits.size).to eq(2)
42-
expect(store.splits_repository.get_change_number).to eq(store.send(:splits_since, -1)[:till])
43+
expect(store.splits_repository.get_change_number).to eq(store.send(:splits_since, -1, -1)[:ff][:t])
44+
expect(store.rule_based_segments_repository.rule_based_segment_names.size).to eq(1)
45+
expect(store.rule_based_segments_repository.get_change_number).to eq(store.send(:splits_since, -1, -1)[:rbs][:t])
4346
end
4447

4548
it 'refreshes splits' do
@@ -48,7 +51,7 @@
4851
active_split = store.splits_repository.splits['test_1_ruby']
4952
expect(active_split[:status]).to eq('ACTIVE')
5053

51-
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1473413807667')
54+
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1473413807667&rbSince=1457726098069')
5255
.to_return(status: 200, body: archived_splits_json)
5356

5457
store.send(:fetch_splits)
@@ -77,40 +80,42 @@
7780
let(:flag_sets_repository) {SplitIoClient::Cache::Repositories::MemoryFlagSetsRepository.new(['set_2']) }
7881
let(:flag_set_filter) {SplitIoClient::Cache::Filter::FlagSetsFilter.new(['set_2']) }
7982
let(:splits_repository) { SplitIoClient::Cache::Repositories::SplitsRepository.new(config, flag_sets_repository, flag_set_filter) }
83+
let(:rule_based_segments_repository) { SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository.new(config) }
8084
let(:telemetry_runtime_producer) { SplitIoClient::Telemetry::RuntimeProducer.new(config) }
81-
let(:store) { described_class.new(splits_repository, '', config, telemetry_runtime_producer) }
85+
let(:store) { described_class.new(splits_repository, rule_based_segments_repository, '', config, telemetry_runtime_producer) }
8286

8387
before do
84-
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1&sets=set_2')
88+
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1&sets=set_2')
8589
.to_return(status: 200, body: active_splits_json)
8690
end
8791

8892
it 'returns splits since' do
89-
splits = store.send(:splits_since, -1)
93+
splits = store.send(:splits_since, -1, -1)
9094

91-
expect(splits[:splits].count).to eq(2)
95+
expect(splits[:ff][:d].count).to eq(2)
9296
end
9397

9498
it 'fetch data in the cache' do
9599
store.send(:fetch_splits)
96100

97101
expect(store.splits_repository.splits.size).to eq(1)
98-
expect(store.splits_repository.get_change_number).to eq(store.send(:splits_since, -1)[:till])
102+
expect(store.splits_repository.get_change_number).to eq(store.send(:splits_since, -1, -1)[:ff][:t])
99103
end
100104

101105
it 'refreshes splits' do
102106
store.send(:fetch_splits)
103107
expect(store.splits_repository.get_split('sample_feature')[:name]).to eq('sample_feature')
104108
expect(store.splits_repository.get_split('test_1_ruby')).to eq(nil)
105109

106-
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1473413807667&sets=set_2')
110+
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1473413807667&rbSince=1457726098069&sets=set_2')
107111
.to_return(status: 200, body: archived_splits_json)
108112

109113
store.send(:fetch_splits)
110114
expect(store.splits_repository.get_split('sample_feature')).to eq(nil)
111115

112116
store.splits_repository.set_change_number(-1)
113-
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1&sets=set_2')
117+
store.rule_based_segments_repository.set_change_number(-1)
118+
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1&sets=set_2')
114119
.to_return(status: 200, body: active_splits_json)
115120

116121
store.send(:fetch_splits)
@@ -129,18 +134,19 @@
129134
let(:flag_sets_repository) {SplitIoClient::Cache::Repositories::RedisFlagSetsRepository.new(config) }
130135
let(:flag_set_filter) {SplitIoClient::Cache::Filter::FlagSetsFilter.new([]) }
131136
let(:splits_repository) { SplitIoClient::Cache::Repositories::SplitsRepository.new(config, flag_sets_repository, flag_set_filter) }
137+
let(:rule_based_segments_repository) { SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository.new(config) }
132138
let(:telemetry_runtime_producer) { SplitIoClient::Telemetry::RuntimeProducer.new(config) }
133-
let(:store) { described_class.new(splits_repository, '', config, telemetry_runtime_producer) }
139+
let(:store) { described_class.new(splits_repository, rule_based_segments_repository, '', config, telemetry_runtime_producer) }
134140

135141
it 'returns splits since' do
136-
splits = store.send(:splits_since, -1)
137-
expect(splits[:splits].count).to eq(2)
142+
splits = store.send(:splits_since, -1, -1)
143+
expect(splits[:ff][:d].count).to eq(2)
138144
end
139145

140146
it 'fetch data in the cache' do
141147
store.send(:fetch_splits)
142148
expect(store.splits_repository.splits.size).to eq(2)
143-
expect(store.splits_repository.get_change_number).to eq(store.send(:splits_since, -1)[:till].to_s)
149+
expect(store.splits_repository.get_change_number).to eq(store.send(:splits_since, -1, -1)[:ff][:t].to_s)
144150
end
145151

146152
it 'refreshes splits' do
@@ -149,7 +155,7 @@
149155
active_split = store.splits_repository.splits['test_1_ruby']
150156
expect(active_split[:status]).to eq('ACTIVE')
151157

152-
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1473413807667')
158+
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1473413807667&rbSince=1457726098069')
153159
.to_return(status: 200, body: archived_splits_json)
154160

155161
store.send(:fetch_splits)

0 commit comments

Comments
 (0)