Skip to content

Commit ced918b

Browse files
authored
Merge pull request #354 from splitio/fix-incorrect-treatment-calculated
Fixed missing segment fetch after an SPLIT_UPDATE
2 parents 8cf57b4 + 72e12b0 commit ced918b

9 files changed

Lines changed: 101 additions & 52 deletions

File tree

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,22 @@ def call
2727
end
2828
end
2929

30+
def fetch_segments_if_not_exists(names)
31+
names.each do |name|
32+
change_number = @segments_repository.get_change_number(name)
33+
34+
fetch_segment(name) if change_number == -1
35+
end
36+
rescue StandardError => error
37+
@config.log_found_exception(__method__.to_s, error)
38+
end
39+
3040
def fetch_segment(name)
3141
@semaphore.synchronize do
3242
segments_api.fetch_segments_by_names([name])
33-
true
3443
end
3544
rescue StandardError => error
3645
@config.log_found_exception(__method__.to_s, error)
37-
false
3846
end
3947

4048
def fetch_segments

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ def fetch_splits
4141
@config.logger.debug("segments seen(#{data[:segment_names].length}): #{data[:segment_names].to_a}") if @config.debug_enabled
4242

4343
@sdk_blocker.splits_ready!
44-
true
44+
45+
data[:segment_names]
4546
end
4647
rescue StandardError => error
4748
@config.log_found_exception(__method__.to_s, error)
48-
false
4949
end
5050

5151
def stop_splits_thread

lib/splitclient-rb/engine/synchronizer.rb

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def initialize(
3030
def sync_all
3131
@config.threads[:sync_all_thread] = Thread.new do
3232
@config.logger.debug('Synchronizing Splits and Segments ...') if @config.debug_enabled
33-
fetch_splits
33+
@split_fetcher.fetch_splits
3434
fetch_segments
3535
end
3636
end
@@ -53,21 +53,12 @@ def stop_periodic_fetch
5353
end
5454

5555
def fetch_splits
56-
back_off = SplitIoClient::SSE::EventSource::BackOff.new(SplitIoClient::Constants::FETCH_BACK_OFF_BASE_RETRIES, 1)
57-
loop do
58-
break if @split_fetcher.fetch_splits
59-
60-
sleep(back_off.interval)
61-
end
56+
segment_names = @split_fetcher.fetch_splits
57+
@segment_fetcher.fetch_segments_if_not_exists(segment_names) unless segment_names.empty?
6258
end
6359

6460
def fetch_segment(name)
65-
back_off = SplitIoClient::SSE::EventSource::BackOff.new(SplitIoClient::Constants::FETCH_BACK_OFF_BASE_RETRIES, 1)
66-
loop do
67-
break if @segment_fetcher.fetch_segment(name)
68-
69-
sleep(back_off.interval)
70-
end
61+
@segment_fetcher.fetch_segment(name)
7162
end
7263

7364
private

lib/splitclient-rb/sse/workers/segments_worker.rb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,13 @@ def stop
4848
def perform
4949
while (item = @queue.pop)
5050
segment_name = item[:segment_name]
51-
change_number = item[:change_number]
52-
since = @segments_repository.get_change_number(segment_name)
51+
cn = item[:change_number]
52+
@config.logger.debug("SegmentsWorker change_number dequeue #{segment_name}, #{cn}")
5353

54-
unless since >= change_number
55-
@config.logger.debug("SegmentsWorker fetch_segment with #{since}")
54+
attempt = 0
55+
while cn > @segments_repository.get_change_number(segment_name).to_i && attempt <= Workers::MAX_RETRIES_ALLOWED
5656
@synchronizer.fetch_segment(segment_name)
57+
attempt += 1
5758
end
5859
end
5960
end

lib/splitclient-rb/sse/workers/splits_worker.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
module SplitIoClient
44
module SSE
55
module Workers
6+
MAX_RETRIES_ALLOWED = 10
7+
68
class SplitsWorker
79
def initialize(synchronizer, config, splits_repository)
810
@synchronizer = synchronizer
@@ -59,11 +61,12 @@ def kill_split(change_number, split_name, default_treatment)
5961

6062
def perform
6163
while (change_number = @queue.pop)
62-
since = @splits_repository.get_change_number
64+
@config.logger.debug("SplitsWorker change_number dequeue #{change_number}")
6365

64-
unless since.to_i >= change_number
65-
@config.logger.debug("SplitsWorker fetch_splits with #{since}")
66+
attempt = 0
67+
while change_number > @splits_repository.get_change_number.to_i && attempt <= Workers::MAX_RETRIES_ALLOWED
6668
@synchronizer.fetch_splits
69+
attempt += 1
6770
end
6871
end
6972
end

spec/engine/synchronizer_spec.rb

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -87,34 +87,22 @@
8787

8888
it 'fetch_splits' do
8989
mock_split_changes(splits)
90+
mock_segment_changes('segment2', segment2, '-1')
91+
mock_segment_changes('segment2', segment2, '1470947453878')
92+
mock_segment_changes('segment3', segment3, '-1')
93+
mock_segment_changes('segment1', segment1, '-1')
94+
mock_segment_changes('segment1', segment1, '1470947453877')
9095

9196
synchronizer.fetch_splits
9297
expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.once
9398
end
9499

95-
it 'fetch_splits with retries' do
96-
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
97-
.to_return({ status: 500 }, { status: 200, body: splits })
98-
99-
synchronizer.fetch_splits
100-
101-
expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.times(2)
102-
end
103-
104100
it 'fetch_segment' do
105101
mock_segment_changes('segment3', segment3, '-1')
106102

107103
synchronizer.fetch_segment('segment3')
108104
expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=-1')).to have_been_made.once
109105
end
110-
111-
it 'fetch_segment with retries' do
112-
stub_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=-1')
113-
.to_return({ status: 500 }, { status: 200, body: segment3 })
114-
115-
synchronizer.fetch_segment('segment3')
116-
expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=-1')).to have_been_made.times(2)
117-
end
118106
end
119107

120108
private

spec/sse/sse_handler_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@
183183
end
184184

185185
context 'SEGMENT UPDATE event' do
186-
it 'must trigger fetch' do
186+
it 'must trigger fetch - with retries' do
187187
mock_server do |server|
188188
server.setup_response('/') do |_, res|
189189
send_content(res, event_segment_update_must_fetch)
@@ -203,7 +203,7 @@
203203

204204
expect(action_event).to eq(SplitIoClient::Constants::PUSH_CONNECTED)
205205
expect(sse_handler.sse_client.connected?).to eq(true)
206-
expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=1470947453877')).to have_been_made.times(1)
206+
expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=1470947453877')).to have_been_made.times(12)
207207

208208
sse_handler.sse_client.close
209209

spec/sse/workers/segments_worker_spec.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@
4141

4242
context 'add segment name to queue' do
4343
it 'must trigger fetch' do
44+
stub_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=1470947453877')
45+
.to_return(status: 200, body:
46+
'{
47+
"name": "segment1",
48+
"added": [],
49+
"removed": [],
50+
"since": 1470947453878,
51+
"till": 1470947453878
52+
}')
53+
4454
worker = subject.new(synchronizer, config, segments_repository)
4555

4656
worker.start
@@ -51,6 +61,17 @@
5161
expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=1470947453877')).to have_been_made.times(2)
5262
end
5363

64+
it 'must trigger fetch - with retries' do
65+
worker = subject.new(synchronizer, config, segments_repository)
66+
67+
worker.start
68+
worker.add_to_queue(1_506_703_262_918, 'segment1')
69+
70+
sleep(1)
71+
72+
expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=1470947453877')).to have_been_made.times(12)
73+
end
74+
5475
it 'must not trigger fetch' do
5576
worker = subject.new(synchronizer, config, segments_repository)
5677

spec/sse/workers/splits_worker_spec.rb

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,44 @@
2727
let(:params) { { split_fetcher: split_fetcher, segment_fetcher: segment_fetcher, imp_counter: impression_counter } }
2828
let(:synchronizer) { SplitIoClient::Engine::Synchronizer.new(repositories, api_key, config, sdk_blocker, params) }
2929

30-
before do
31-
mock_split_changes(splits)
32-
mock_segment_changes('segment1', segment1, '-1')
33-
mock_segment_changes('segment1', segment1, '1470947453877')
34-
mock_segment_changes('segment2', segment2, '-1')
35-
mock_segment_changes('segment2', segment2, '1470947453878')
36-
mock_segment_changes('segment3', segment3, '-1')
37-
38-
split_fetcher.fetch_splits
30+
it 'add change number - must tigger fetcch - with retries' do
31+
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
32+
.to_return(status: 200, body:
33+
'{
34+
"splits": [],
35+
"since": -1,
36+
"till": 1506703262918
37+
}')
38+
39+
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918')
40+
.to_return(status: 200, body:
41+
'{
42+
"splits": [],
43+
"since": 1506703262918,
44+
"till": 1506703262918
45+
}')
46+
47+
worker = subject.new(synchronizer, config, splits_repository)
48+
worker.start
49+
worker.add_to_queue(1_506_703_262_919)
50+
51+
sleep(1)
52+
53+
expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918')).to have_been_made.times(10)
3954
end
4055

4156
context 'add change number to queue' do
57+
before do
58+
mock_split_changes(splits)
59+
mock_segment_changes('segment1', segment1, '-1')
60+
mock_segment_changes('segment1', segment1, '1470947453877')
61+
mock_segment_changes('segment2', segment2, '-1')
62+
mock_segment_changes('segment2', segment2, '1470947453878')
63+
mock_segment_changes('segment3', segment3, '-1')
64+
65+
split_fetcher.fetch_splits
66+
end
67+
4268
it 'must trigger fetch' do
4369
worker = subject.new(synchronizer, config, splits_repository)
4470
worker.start
@@ -71,6 +97,17 @@
7197
end
7298

7399
context 'kill split notification' do
100+
before do
101+
mock_split_changes(splits)
102+
mock_segment_changes('segment1', segment1, '-1')
103+
mock_segment_changes('segment1', segment1, '1470947453877')
104+
mock_segment_changes('segment2', segment2, '-1')
105+
mock_segment_changes('segment2', segment2, '1470947453878')
106+
mock_segment_changes('segment3', segment3, '-1')
107+
108+
split_fetcher.fetch_splits
109+
end
110+
74111
it 'must kill split and trigger fetch' do
75112
worker = subject.new(synchronizer, config, splits_repository)
76113

0 commit comments

Comments
 (0)