Skip to content

Commit 7df074a

Browse files
committed
splits retries implementation
1 parent 9f2b8b0 commit 7df074a

11 files changed

Lines changed: 95 additions & 22 deletions

File tree

.rubocop.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Metrics/LineLength:
3131
- spec/engine/sync_manager_spec.rb
3232
- spec/engine/auth_api_client_spec.rb
3333
- spec/telemetry/synchronizer_spec.rb
34+
- spec/splitclient/split_config_spec.rb
3435

3536
Style/BracesAroundHashParameters:
3637
Exclude:
@@ -62,3 +63,4 @@ AllCops:
6263
- lib/splitclient-rb/engine/models/**/*
6364
- lib/splitclient-rb/engine/parser/**/*
6465
- spec/telemetry/synchronizer_spec.rb
66+
- lib/splitclient-rb/engine/synchronizer.rb

lib/splitclient-rb/engine/synchronizer.rb

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ class Synchronizer
66
include SplitIoClient::Cache::Fetchers
77
include SplitIoClient::Cache::Senders
88

9-
ON_DEMAND_FETCH_BACKOFF_BASE_MS = 10_000
10-
ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_MS = 60_000
9+
ON_DEMAND_FETCH_BACKOFF_BASE_SECONDS = 10
10+
ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_SECONDS = 60
1111
ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES = 10
1212

1313
def initialize(
@@ -29,7 +29,6 @@ def initialize(
2929
@impressions_api = SplitIoClient::Api::Impressions.new(@api_key, @config, params[:telemetry_runtime_producer])
3030
@impression_counter = params[:imp_counter]
3131
@telemetry_synchronizer = params[:telemetry_synchronizer]
32-
@backoff = new SSE::EventSource::BackOff.new()
3332
end
3433

3534
def sync_all
@@ -58,14 +57,15 @@ def stop_periodic_fetch
5857
end
5958

6059
def fetch_splits(target_change_number)
61-
return if target_change_number <= @splits_repository.get_change_number
60+
return if target_change_number <= @splits_repository.get_change_number.to_i
6261

6362
fetch_options = { cache_control_headers: true, till: nil }
6463

6564
result = attempt_splits_sync(target_change_number,
6665
fetch_options,
6766
@config.on_demand_fetch_max_retries,
68-
@config.on_demand_fetch_retry_delay_ms)
67+
@config.on_demand_fetch_retry_delay_seconds,
68+
false)
6969

7070
attempts = @config.on_demand_fetch_max_retries - result[:remaining_attempts]
7171
if result[:success]
@@ -79,7 +79,8 @@ def fetch_splits(target_change_number)
7979
result = attempt_splits_sync(target_change_number,
8080
fetch_options,
8181
ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES,
82-
@config.on_demand_fetch_retry_delay_ms)
82+
nil,
83+
true)
8384

8485
attempts = @config.on_demand_fetch_max_retries - result[:remaining_attempts]
8586

@@ -100,8 +101,9 @@ def fetch_segment(name)
100101

101102
private
102103

103-
def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_ms)
104+
def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_seconds, with_backoff)
104105
remaining_attempts = max_retries
106+
backoff = SSE::EventSource::BackOff.new(ON_DEMAND_FETCH_BACKOFF_BASE_SECONDS, 0, ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_SECONDS) if with_backoff
105107

106108
loop do
107109
remaining_attempts -= 1
@@ -111,7 +113,8 @@ def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_ms)
111113
return split_sync_result(true, remaining_attempts, segment_names) if target_cn <= @splits_repository.get_change_number
112114
return split_sync_result(false, remaining_attempts, segment_names) if remaining_attempts <= 0
113115

114-
sleep(retry_delay_ms)
116+
delay = with_backoff ? backoff.interval : retry_delay_seconds
117+
sleep(delay)
115118
end
116119
end
117120

lib/splitclient-rb/split_config.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def initialize(opts = {})
113113

114114
@sdk_start_time = Time.now
115115

116-
@on_demand_fetch_retry_delay_ms = SplitConfig.default_on_demand_fetch_retry_delay_ms
116+
@on_demand_fetch_retry_delay_seconds = SplitConfig.default_on_demand_fetch_retry_delay_seconds
117117
@on_demand_fetch_max_retries = SplitConfig.default_on_demand_fetch_max_retries
118118

119119
startup_log
@@ -281,11 +281,11 @@ def initialize(opts = {})
281281

282282
attr_accessor :sdk_start_time
283283

284-
attr_accessor :on_demand_fetch_retry_delay_ms
284+
attr_accessor :on_demand_fetch_retry_delay_seconds
285285
attr_accessor :on_demand_fetch_max_retries
286286

287-
def self.default_on_demand_fetch_retry_delay_ms
288-
50
287+
def self.default_on_demand_fetch_retry_delay_seconds
288+
0.05
289289
end
290290

291291
def self.default_on_demand_fetch_max_retries

lib/splitclient-rb/sse/event_source/back_off.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,20 @@
33
module SplitIoClient
44
module SSE
55
module EventSource
6+
BACKOFF_MAX_ALLOWED = 1.8
67
class BackOff
7-
def initialize(back_off_base, attempt = 0)
8+
def initialize(back_off_base, attempt = 0, max_allowed = BACKOFF_MAX_ALLOWED)
89
@attempt = attempt
910
@back_off_base = back_off_base
11+
@max_allowed = max_allowed
1012
end
1113

1214
def interval
15+
interval = 0
1316
interval = (@back_off_base * (2**@attempt)) if @attempt.positive?
1417
@attempt += 1
1518

16-
interval || 0
19+
interval >= @max_allowed ? @max_allowed : interval
1720
end
1821

1922
def reset

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
module SplitIoClient
44
module SSE
55
module Workers
6+
MAX_RETRIES_ALLOWED = 10
67
class SegmentsWorker
78
def initialize(synchronizer, config, segments_repository)
89
@synchronizer = synchronizer
@@ -52,7 +53,7 @@ def perform
5253
@config.logger.debug("SegmentsWorker change_number dequeue #{segment_name}, #{cn}")
5354

5455
attempt = 0
55-
while cn > @segments_repository.get_change_number(segment_name).to_i && attempt <= Workers::MAX_RETRIES_ALLOWED
56+
while cn > @segments_repository.get_change_number(segment_name).to_i && attempt <= MAX_RETRIES_ALLOWED
5657
@synchronizer.fetch_segment(segment_name)
5758
attempt += 1
5859
end

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def kill_split(change_number, split_name, default_treatment)
6060
def perform
6161
while (change_number = @queue.pop)
6262
@config.logger.debug("SplitsWorker change_number dequeue #{change_number}")
63-
@synchronizer.fetch_splits
63+
@synchronizer.fetch_splits(change_number)
6464
end
6565
end
6666

spec/engine/synchronizer_spec.rb

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,43 @@
9292
mock_segment_changes('segment1', segment1, '-1')
9393
mock_segment_changes('segment1', segment1, '1470947453877')
9494

95-
synchronizer.fetch_splits
95+
synchronizer.fetch_splits(0)
9696
expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.once
9797
end
9898

99+
it 'fetch_splits - ' do
100+
sync = subject.new(repositories, api_key, config, sdk_blocker, parameters)
101+
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
102+
.to_return(status: 200, body:
103+
'{
104+
"splits": [],
105+
"since": -1,
106+
"till": 1506703262918
107+
}')
108+
109+
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918')
110+
.to_return(status: 200, body:
111+
'{
112+
"splits": [],
113+
"since": 1506703262918,
114+
"till": 1506703262918
115+
}')
116+
117+
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918&till=1506703262920')
118+
.to_return(status: 200, body:
119+
'{
120+
"splits": [],
121+
"since": 1506703262918,
122+
"till": 1506703262921
123+
}')
124+
125+
sync.fetch_splits(1_506_703_262_920)
126+
127+
expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.once
128+
expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918')).to have_been_made.times(9)
129+
expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918&till=1506703262920')).to have_been_made.once
130+
end
131+
99132
it 'fetch_segment' do
100133
mock_segment_changes('segment3', segment3, '-1')
101134

spec/splitclient/split_config_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
expect(configs.ip_addresses_enabled).to eq default_ip
3232
expect(configs.machine_name).to eq SplitIoClient::SplitConfig.machine_hostname(default_ip, nil, :redis)
3333
expect(configs.machine_ip).to eq SplitIoClient::SplitConfig.machine_ip(default_ip, nil, :redis)
34-
expect(configs.on_demand_fetch_retry_delay_ms).to eq SplitIoClient::SplitConfig.default_on_demand_fetch_retry_delay_ms
34+
expect(configs.on_demand_fetch_retry_delay_seconds).to eq SplitIoClient::SplitConfig.default_on_demand_fetch_retry_delay_seconds
3535
expect(configs.on_demand_fetch_max_retries).to eq SplitIoClient::SplitConfig.default_on_demand_fetch_max_retries
3636
end
3737

spec/sse/event_source/back_off_spec.rb

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
let(:log) { StringIO.new }
1010

1111
it 'get intervals and reset attemps' do
12-
back_off = subject.new(1)
12+
back_off = subject.new(1, 0, 5)
1313

1414
firts_interval = back_off.interval
1515
expect(firts_interval).to eq(0)
@@ -27,7 +27,7 @@
2727

2828
it 'with custom config' do
2929
streaming_reconnect_back_off_base = 5
30-
back_off = subject.new(streaming_reconnect_back_off_base)
30+
back_off = subject.new(streaming_reconnect_back_off_base, 0, 30)
3131

3232
firts_interval = back_off.interval
3333
expect(firts_interval).to eq(0)
@@ -42,4 +42,34 @@
4242
reset_interval = back_off.interval
4343
expect(reset_interval).to eq(0)
4444
end
45+
46+
it 'with max' do
47+
streaming_reconnect_back_off_base = 5
48+
back_off = subject.new(streaming_reconnect_back_off_base, 0, 30)
49+
50+
firts_interval = back_off.interval
51+
expect(firts_interval).to eq(0)
52+
53+
second_interval = back_off.interval
54+
expect(second_interval).to eq(10)
55+
56+
third_interval = back_off.interval
57+
expect(third_interval).to eq(20)
58+
59+
third_interval = back_off.interval
60+
expect(third_interval).to eq(30)
61+
62+
third_interval = back_off.interval
63+
expect(third_interval).to eq(30)
64+
65+
third_interval = back_off.interval
66+
expect(third_interval).to eq(30)
67+
68+
third_interval = back_off.interval
69+
expect(third_interval).to eq(30)
70+
71+
back_off.reset
72+
reset_interval = back_off.interval
73+
expect(reset_interval).to eq(0)
74+
end
4575
end

spec/sse/sse_handler_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
mock_segment_changes('segment2', segment2, '1470947453878')
6363
mock_segment_changes('segment3', segment3, '-1')
6464

65-
synchronizer.fetch_splits
65+
synchronizer.fetch_splits(0)
6666
end
6767

6868
context 'SPLIT UPDATE event' do

0 commit comments

Comments
 (0)