From e1da666f0d94652f980dc3a3e7b670bf47033c4c Mon Sep 17 00:00:00 2001 From: Mauro Sanz Date: Fri, 16 Jul 2021 17:11:10 -0300 Subject: [PATCH 1/6] add configs and update api clients --- .../cache/fetchers/segment_fetcher.rb | 11 +++++--- .../cache/fetchers/split_fetcher.rb | 8 +++--- lib/splitclient-rb/engine/api/segments.rb | 11 +++++--- lib/splitclient-rb/engine/api/splits.rb | 8 +++--- lib/splitclient-rb/engine/synchronizer.rb | 10 ++++---- lib/splitclient-rb/split_config.rb | 14 +++++++++++ spec/engine/api/segments_spec.rb | 25 ++++++++++++++++++- spec/engine/api/splits_spec.rb | 25 +++++++++++++++++-- spec/splitclient/split_config_spec.rb | 2 ++ 9 files changed, 91 insertions(+), 23 deletions(-) diff --git a/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb b/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb index 85ed13ce..efd24bd2 100644 --- a/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb +++ b/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb @@ -30,16 +30,19 @@ def call def fetch_segments_if_not_exists(names, cache_control_headers = false) names.each do |name| change_number = @segments_repository.get_change_number(name) - - fetch_segment(name, cache_control_headers) if change_number == -1 + + if change_number == -1 + fetch_options = { cache_control_headers: cache_control_headers, till: nil } + fetch_segment(name, fetch_options) if change_number == -1 + end end rescue StandardError => error @config.log_found_exception(__method__.to_s, error) end - def fetch_segment(name, cache_control_headers = false) + def fetch_segment(name, fetch_options = { cache_control_headers: false, till: nil }) @semaphore.synchronize do - segments_api.fetch_segments_by_names([name], cache_control_headers) + segments_api.fetch_segments_by_names([name], fetch_options) end rescue StandardError => error @config.log_found_exception(__method__.to_s, error) diff --git a/lib/splitclient-rb/cache/fetchers/split_fetcher.rb b/lib/splitclient-rb/cache/fetchers/split_fetcher.rb index 91cb311b..51534bab 100644 --- a/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +++ b/lib/splitclient-rb/cache/fetchers/split_fetcher.rb @@ -27,9 +27,9 @@ def call end end - def fetch_splits(cache_control_headers = false) + def fetch_splits(fetch_options = { cache_control_headers: false, till: nil }) @semaphore.synchronize do - data = splits_since(@splits_repository.get_change_number, cache_control_headers) + data = splits_since(@splits_repository.get_change_number, fetch_options) data[:splits] && data[:splits].each do |split| add_split_unless_archived(split) @@ -68,8 +68,8 @@ def splits_thread end end - def splits_since(since, cache_control_headers = false) - splits_api.since(since, cache_control_headers) + def splits_since(since, fetch_options = { cache_control_headers: false, till: nil }) + splits_api.since(since, fetch_options) end def add_split_unless_archived(split) diff --git a/lib/splitclient-rb/engine/api/segments.rb b/lib/splitclient-rb/engine/api/segments.rb index ae27453d..0c16adc7 100644 --- a/lib/splitclient-rb/engine/api/segments.rb +++ b/lib/splitclient-rb/engine/api/segments.rb @@ -11,13 +11,13 @@ def initialize(api_key, segments_repository, config, telemetry_runtime_producer) @telemetry_runtime_producer = telemetry_runtime_producer end - def fetch_segments_by_names(names, cache_control_headers = false) + def fetch_segments_by_names(names, fetch_options = { cache_control_headers: false, till: nil }) return if names.nil? || names.empty? names.each do |name| since = @segments_repository.get_change_number(name) loop do - segment = fetch_segment_changes(name, since, cache_control_headers) + segment = fetch_segment_changes(name, since, fetch_options) @segments_repository.add_to_segment(segment) @config.split_logger.log_if_debug("Segment #{name} fetched before: #{since}, \ @@ -32,9 +32,12 @@ def fetch_segments_by_names(names, cache_control_headers = false) private - def fetch_segment_changes(name, since, cache_control_headers = false) + def fetch_segment_changes(name, since, fetch_options = { cache_control_headers: false, till: nil }) start = Time.now - response = get_api("#{@config.base_uri}/segmentChanges/#{name}", @api_key, { since: since }, cache_control_headers) + + params = { since: since } + params[:till] = fetch_options[:till] unless fetch_options[:till].nil? + response = get_api("#{@config.base_uri}/segmentChanges/#{name}", @api_key, params, fetch_options[:cache_control_headers]) if response.success? segment = JSON.parse(response.body, symbolize_names: true) diff --git a/lib/splitclient-rb/engine/api/splits.rb b/lib/splitclient-rb/engine/api/splits.rb index 3d0c1197..99bbe5ce 100644 --- a/lib/splitclient-rb/engine/api/splits.rb +++ b/lib/splitclient-rb/engine/api/splits.rb @@ -10,10 +10,12 @@ def initialize(api_key, config, telemetry_runtime_producer) @telemetry_runtime_producer = telemetry_runtime_producer end - def since(since, cache_control_headers = false) + def since(since, fetch_options = { cache_control_headers: false, till: nil }) start = Time.now - - response = get_api("#{@config.base_uri}/splitChanges", @api_key, { since: since }, cache_control_headers) + + params = { since: since } + params[:till] = fetch_options[:till] unless fetch_options[:till].nil? + response = get_api("#{@config.base_uri}/splitChanges", @api_key, params, fetch_options[:cache_control_headers]) if response.success? result = splits_with_segment_names(response.body) diff --git a/lib/splitclient-rb/engine/synchronizer.rb b/lib/splitclient-rb/engine/synchronizer.rb index 069521d7..5f23b4cb 100644 --- a/lib/splitclient-rb/engine/synchronizer.rb +++ b/lib/splitclient-rb/engine/synchronizer.rb @@ -6,8 +6,6 @@ class Synchronizer include SplitIoClient::Cache::Fetchers include SplitIoClient::Cache::Senders - FORCE_CACHE_CONTROL_HEADERS = true - def initialize( repositories, api_key, @@ -55,12 +53,14 @@ def stop_periodic_fetch end def fetch_splits - segment_names = @split_fetcher.fetch_splits(FORCE_CACHE_CONTROL_HEADERS) - @segment_fetcher.fetch_segments_if_not_exists(segment_names, FORCE_CACHE_CONTROL_HEADERS) unless segment_names.empty? + fetch_options = { cache_control_headers: true, till: nil } + segment_names = @split_fetcher.fetch_splits(fetch_options) + @segment_fetcher.fetch_segments_if_not_exists(segment_names, true) unless segment_names.empty? end def fetch_segment(name) - @segment_fetcher.fetch_segment(name, FORCE_CACHE_CONTROL_HEADERS) + fetch_options = { cache_control_headers: true, till: nil } + @segment_fetcher.fetch_segment(name, fetch_options) end private diff --git a/lib/splitclient-rb/split_config.rb b/lib/splitclient-rb/split_config.rb index 468c3b0a..7886e99d 100644 --- a/lib/splitclient-rb/split_config.rb +++ b/lib/splitclient-rb/split_config.rb @@ -113,6 +113,9 @@ def initialize(opts = {}) @sdk_start_time = Time.now + @on_demand_fetch_retry_delay_ms = SplitConfig.default_on_demand_fetch_retry_delay_ms + @on_demand_fetch_max_retries = SplitConfig.default_on_demand_fetch_max_retries + startup_log end @@ -278,6 +281,17 @@ def initialize(opts = {}) attr_accessor :sdk_start_time + attr_accessor :on_demand_fetch_retry_delay_ms + attr_accessor :on_demand_fetch_max_retries + + def self.default_on_demand_fetch_retry_delay_ms + 50 + end + + def self.default_on_demand_fetch_max_retries + 10 + end + def self.default_impressions_mode :optimized end diff --git a/spec/engine/api/segments_spec.rb b/spec/engine/api/segments_spec.rb index af112ae1..755a2890 100644 --- a/spec/engine/api/segments_spec.rb +++ b/spec/engine/api/segments_spec.rb @@ -43,6 +43,28 @@ expect(log.string).to include ':added=>["max", "dan"]' end + it 'returns fetch_segments - with till param' do + stub_request(:get, 'https://sdk.split.io/api/segmentChanges/employees?since=-1&till=222334') + .with(headers: { + 'Accept' => '*/*', + 'Accept-Encoding' => 'gzip', + 'Authorization' => 'Bearer', + 'Connection' => 'keep-alive', + 'Keep-Alive' => '30', + 'Splitsdkversion' => "#{config.language}-#{config.version}" + }) + .to_return(status: 200, body: segments) + + fetch_options = { cache_control_headers: false, till: 222_334 } + returned_segment = segments_api.send(:fetch_segment_changes, 'employees', -1, fetch_options) + + expect(returned_segment[:name]).to eq 'employees' + + expect(log.string).to include "'employees' segment retrieved." + expect(log.string).to include "'employees' 2 added keys" + expect(log.string).to include ':added=>["max", "dan"]' + end + it 'returns fetch_segments - checking headers when cache_control_headers is true' do stub_request(:get, 'https://sdk.split.io/api/segmentChanges/employees?since=-1') .with(headers: { @@ -56,7 +78,8 @@ }) .to_return(status: 200, body: segments) - returned_segment = segments_api.send(:fetch_segment_changes, 'employees', -1, true) + fetch_options = { cache_control_headers: true, till: nil } + returned_segment = segments_api.send(:fetch_segment_changes, 'employees', -1, fetch_options) expect(returned_segment[:name]).to eq 'employees' diff --git a/spec/engine/api/splits_spec.rb b/spec/engine/api/splits_spec.rb index 374fda99..bc2fcb03 100644 --- a/spec/engine/api/splits_spec.rb +++ b/spec/engine/api/splits_spec.rb @@ -47,7 +47,27 @@ expect(log.string).to include returned_splits.to_s end - it 'returns the splits - checking headers when cache_control_headers is true ' do + it 'returns the splits - with till param' do + stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1&till=123123') + .with(headers: { + 'Accept' => '*/*', + 'Accept-Encoding' => 'gzip', + 'Authorization' => 'Bearer', + 'Connection' => 'keep-alive', + 'Keep-Alive' => '30', + 'Splitsdkversion' => "#{config.language}-#{config.version}" + }) + .to_return(status: 200, body: splits) + + fetch_options = { cache_control_headers: false, till: 123_123 } + returned_splits = splits_api.since(-1, fetch_options) + expect(returned_splits[:segment_names]).to eq(Set.new(%w[demo employees])) + + expect(log.string).to include '2 splits retrieved. since=-1' + expect(log.string).to include returned_splits.to_s + end + + it 'returns the splits - checking headers when cache_control_headers is true' do stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') .with(headers: { 'Accept' => '*/*', @@ -60,7 +80,8 @@ }) .to_return(status: 200, body: splits) - returned_splits = splits_api.since(-1, true) + fetch_options = { cache_control_headers: true, till: nil } + returned_splits = splits_api.since(-1, fetch_options) expect(returned_splits[:segment_names]).to eq(Set.new(%w[demo employees])) expect(log.string).to include '2 splits retrieved. since=-1' diff --git a/spec/splitclient/split_config_spec.rb b/spec/splitclient/split_config_spec.rb index 8cb8ff04..97b675f2 100644 --- a/spec/splitclient/split_config_spec.rb +++ b/spec/splitclient/split_config_spec.rb @@ -31,6 +31,8 @@ expect(configs.ip_addresses_enabled).to eq default_ip expect(configs.machine_name).to eq SplitIoClient::SplitConfig.machine_hostname(default_ip, nil, :redis) expect(configs.machine_ip).to eq SplitIoClient::SplitConfig.machine_ip(default_ip, nil, :redis) + expect(configs.on_demand_fetch_retry_delay_ms).to eq SplitIoClient::SplitConfig.default_on_demand_fetch_retry_delay_ms + expect(configs.on_demand_fetch_max_retries).to eq SplitIoClient::SplitConfig.default_on_demand_fetch_max_retries end it 'stores and retrieves correctly the customized values' do From 9f2b8b0c6778bd279fd9fe5b9875b9dd3ae086c7 Mon Sep 17 00:00:00 2001 From: Mauro Sanz Date: Tue, 20 Jul 2021 10:42:37 -0300 Subject: [PATCH 2/6] splits logic implementation --- lib/splitclient-rb/engine/synchronizer.rb | 60 ++++++++++++++++++- .../sse/workers/splits_worker.rb | 9 +-- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/lib/splitclient-rb/engine/synchronizer.rb b/lib/splitclient-rb/engine/synchronizer.rb index 5f23b4cb..7508de3b 100644 --- a/lib/splitclient-rb/engine/synchronizer.rb +++ b/lib/splitclient-rb/engine/synchronizer.rb @@ -6,6 +6,10 @@ class Synchronizer include SplitIoClient::Cache::Fetchers include SplitIoClient::Cache::Senders + ON_DEMAND_FETCH_BACKOFF_BASE_MS = 10_000 + ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_MS = 60_000 + ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES = 10 + def initialize( repositories, api_key, @@ -25,6 +29,7 @@ def initialize( @impressions_api = SplitIoClient::Api::Impressions.new(@api_key, @config, params[:telemetry_runtime_producer]) @impression_counter = params[:imp_counter] @telemetry_synchronizer = params[:telemetry_synchronizer] + @backoff = new SSE::EventSource::BackOff.new() end def sync_all @@ -52,10 +57,40 @@ def stop_periodic_fetch @segment_fetcher.stop_segments_thread end - def fetch_splits + def fetch_splits(target_change_number) + return if target_change_number <= @splits_repository.get_change_number + fetch_options = { cache_control_headers: true, till: nil } - segment_names = @split_fetcher.fetch_splits(fetch_options) - @segment_fetcher.fetch_segments_if_not_exists(segment_names, true) unless segment_names.empty? + + result = attempt_splits_sync(target_change_number, + fetch_options, + @config.on_demand_fetch_max_retries, + @config.on_demand_fetch_retry_delay_ms) + + attempts = @config.on_demand_fetch_max_retries - result[:remaining_attempts] + if result[:success] + @segment_fetcher.fetch_segments_if_not_exists(result[:segment_names], true) unless result[:segment_names].empty? + @config.logger.debug("Refresh completed in #{attempts} attempts.") if @config.debug_enabled + + return + end + + fetch_options[:till] = target_change_number + result = attempt_splits_sync(target_change_number, + fetch_options, + ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES, + @config.on_demand_fetch_retry_delay_ms) + + attempts = @config.on_demand_fetch_max_retries - result[:remaining_attempts] + + if result[:success] + @segment_fetcher.fetch_segments_if_not_exists(result[:segment_names], true) unless result[:segment_names].empty? + @config.logger.debug("Refresh completed bypassing the CDN in #{attempts} attempts.") + else + @config.logger.debug("No changes fetched after #{attempts} attempts with CDN bypassed.") + end + rescue StandardError => error + @config.log_found_exception(__method__.to_s, error) end def fetch_segment(name) @@ -65,6 +100,21 @@ def fetch_segment(name) private + def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_ms) + remaining_attempts = max_retries + + loop do + remaining_attempts -= 1 + + segment_names = @split_fetcher.fetch_splits(fetch_options) + + return split_sync_result(true, remaining_attempts, segment_names) if target_cn <= @splits_repository.get_change_number + return split_sync_result(false, remaining_attempts, segment_names) if remaining_attempts <= 0 + + sleep(retry_delay_ms) + end + end + def fetch_segments @segment_fetcher.fetch_segments end @@ -87,6 +137,10 @@ def impressions_count_sender def start_telemetry_sync_task Telemetry::SyncTask.new(@config, @telemetry_synchronizer).call end + + def split_sync_result(success, remaining_attempts, segment_names) + { success: success, remaining_attempts: remaining_attempts, segment_names: segment_names } + end end end end diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index ba4fd527..a05f63bb 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -3,8 +3,6 @@ module SplitIoClient module SSE module Workers - MAX_RETRIES_ALLOWED = 10 - class SplitsWorker def initialize(synchronizer, config, splits_repository) @synchronizer = synchronizer @@ -62,12 +60,7 @@ def kill_split(change_number, split_name, default_treatment) def perform while (change_number = @queue.pop) @config.logger.debug("SplitsWorker change_number dequeue #{change_number}") - - attempt = 0 - while change_number > @splits_repository.get_change_number.to_i && attempt <= Workers::MAX_RETRIES_ALLOWED - @synchronizer.fetch_splits - attempt += 1 - end + @synchronizer.fetch_splits end end From 7df074a77c7d5b3d781346ed742e3e21ca4b3a60 Mon Sep 17 00:00:00 2001 From: Mauro Sanz Date: Tue, 20 Jul 2021 17:49:08 -0300 Subject: [PATCH 3/6] splits retries implementation --- .rubocop.yml | 2 ++ lib/splitclient-rb/engine/synchronizer.rb | 19 +++++----- lib/splitclient-rb/split_config.rb | 8 ++--- .../sse/event_source/back_off.rb | 7 ++-- .../sse/workers/segments_worker.rb | 3 +- .../sse/workers/splits_worker.rb | 2 +- spec/engine/synchronizer_spec.rb | 35 ++++++++++++++++++- spec/splitclient/split_config_spec.rb | 2 +- spec/sse/event_source/back_off_spec.rb | 34 ++++++++++++++++-- spec/sse/sse_handler_spec.rb | 2 +- spec/sse/workers/splits_worker_spec.rb | 3 +- 11 files changed, 95 insertions(+), 22 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 9806211d..74645582 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -31,6 +31,7 @@ Metrics/LineLength: - spec/engine/sync_manager_spec.rb - spec/engine/auth_api_client_spec.rb - spec/telemetry/synchronizer_spec.rb + - spec/splitclient/split_config_spec.rb Style/BracesAroundHashParameters: Exclude: @@ -62,3 +63,4 @@ AllCops: - lib/splitclient-rb/engine/models/**/* - lib/splitclient-rb/engine/parser/**/* - spec/telemetry/synchronizer_spec.rb + - lib/splitclient-rb/engine/synchronizer.rb diff --git a/lib/splitclient-rb/engine/synchronizer.rb b/lib/splitclient-rb/engine/synchronizer.rb index 7508de3b..ac4df696 100644 --- a/lib/splitclient-rb/engine/synchronizer.rb +++ b/lib/splitclient-rb/engine/synchronizer.rb @@ -6,8 +6,8 @@ class Synchronizer include SplitIoClient::Cache::Fetchers include SplitIoClient::Cache::Senders - ON_DEMAND_FETCH_BACKOFF_BASE_MS = 10_000 - ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_MS = 60_000 + ON_DEMAND_FETCH_BACKOFF_BASE_SECONDS = 10 + ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_SECONDS = 60 ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES = 10 def initialize( @@ -29,7 +29,6 @@ def initialize( @impressions_api = SplitIoClient::Api::Impressions.new(@api_key, @config, params[:telemetry_runtime_producer]) @impression_counter = params[:imp_counter] @telemetry_synchronizer = params[:telemetry_synchronizer] - @backoff = new SSE::EventSource::BackOff.new() end def sync_all @@ -58,14 +57,15 @@ def stop_periodic_fetch end def fetch_splits(target_change_number) - return if target_change_number <= @splits_repository.get_change_number + return if target_change_number <= @splits_repository.get_change_number.to_i fetch_options = { cache_control_headers: true, till: nil } result = attempt_splits_sync(target_change_number, fetch_options, @config.on_demand_fetch_max_retries, - @config.on_demand_fetch_retry_delay_ms) + @config.on_demand_fetch_retry_delay_seconds, + false) attempts = @config.on_demand_fetch_max_retries - result[:remaining_attempts] if result[:success] @@ -79,7 +79,8 @@ def fetch_splits(target_change_number) result = attempt_splits_sync(target_change_number, fetch_options, ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES, - @config.on_demand_fetch_retry_delay_ms) + nil, + true) attempts = @config.on_demand_fetch_max_retries - result[:remaining_attempts] @@ -100,8 +101,9 @@ def fetch_segment(name) private - def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_ms) + def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_seconds, with_backoff) remaining_attempts = max_retries + backoff = SSE::EventSource::BackOff.new(ON_DEMAND_FETCH_BACKOFF_BASE_SECONDS, 0, ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_SECONDS) if with_backoff loop do remaining_attempts -= 1 @@ -111,7 +113,8 @@ def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_ms) return split_sync_result(true, remaining_attempts, segment_names) if target_cn <= @splits_repository.get_change_number return split_sync_result(false, remaining_attempts, segment_names) if remaining_attempts <= 0 - sleep(retry_delay_ms) + delay = with_backoff ? backoff.interval : retry_delay_seconds + sleep(delay) end end diff --git a/lib/splitclient-rb/split_config.rb b/lib/splitclient-rb/split_config.rb index 7886e99d..837e8a68 100644 --- a/lib/splitclient-rb/split_config.rb +++ b/lib/splitclient-rb/split_config.rb @@ -113,7 +113,7 @@ def initialize(opts = {}) @sdk_start_time = Time.now - @on_demand_fetch_retry_delay_ms = SplitConfig.default_on_demand_fetch_retry_delay_ms + @on_demand_fetch_retry_delay_seconds = SplitConfig.default_on_demand_fetch_retry_delay_seconds @on_demand_fetch_max_retries = SplitConfig.default_on_demand_fetch_max_retries startup_log @@ -281,11 +281,11 @@ def initialize(opts = {}) attr_accessor :sdk_start_time - attr_accessor :on_demand_fetch_retry_delay_ms + attr_accessor :on_demand_fetch_retry_delay_seconds attr_accessor :on_demand_fetch_max_retries - def self.default_on_demand_fetch_retry_delay_ms - 50 + def self.default_on_demand_fetch_retry_delay_seconds + 0.05 end def self.default_on_demand_fetch_max_retries diff --git a/lib/splitclient-rb/sse/event_source/back_off.rb b/lib/splitclient-rb/sse/event_source/back_off.rb index b9a2f8c0..ea21fc85 100644 --- a/lib/splitclient-rb/sse/event_source/back_off.rb +++ b/lib/splitclient-rb/sse/event_source/back_off.rb @@ -3,17 +3,20 @@ module SplitIoClient module SSE module EventSource + BACKOFF_MAX_ALLOWED = 1.8 class BackOff - def initialize(back_off_base, attempt = 0) + def initialize(back_off_base, attempt = 0, max_allowed = BACKOFF_MAX_ALLOWED) @attempt = attempt @back_off_base = back_off_base + @max_allowed = max_allowed end def interval + interval = 0 interval = (@back_off_base * (2**@attempt)) if @attempt.positive? @attempt += 1 - interval || 0 + interval >= @max_allowed ? @max_allowed : interval end def reset diff --git a/lib/splitclient-rb/sse/workers/segments_worker.rb b/lib/splitclient-rb/sse/workers/segments_worker.rb index 6d5768e8..d078a356 100644 --- a/lib/splitclient-rb/sse/workers/segments_worker.rb +++ b/lib/splitclient-rb/sse/workers/segments_worker.rb @@ -3,6 +3,7 @@ module SplitIoClient module SSE module Workers + MAX_RETRIES_ALLOWED = 10 class SegmentsWorker def initialize(synchronizer, config, segments_repository) @synchronizer = synchronizer @@ -52,7 +53,7 @@ def perform @config.logger.debug("SegmentsWorker change_number dequeue #{segment_name}, #{cn}") attempt = 0 - while cn > @segments_repository.get_change_number(segment_name).to_i && attempt <= Workers::MAX_RETRIES_ALLOWED + while cn > @segments_repository.get_change_number(segment_name).to_i && attempt <= MAX_RETRIES_ALLOWED @synchronizer.fetch_segment(segment_name) attempt += 1 end diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index a05f63bb..03c780b1 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -60,7 +60,7 @@ def kill_split(change_number, split_name, default_treatment) def perform while (change_number = @queue.pop) @config.logger.debug("SplitsWorker change_number dequeue #{change_number}") - @synchronizer.fetch_splits + @synchronizer.fetch_splits(change_number) end end diff --git a/spec/engine/synchronizer_spec.rb b/spec/engine/synchronizer_spec.rb index 2ad3acfb..f79ee117 100644 --- a/spec/engine/synchronizer_spec.rb +++ b/spec/engine/synchronizer_spec.rb @@ -92,10 +92,43 @@ mock_segment_changes('segment1', segment1, '-1') mock_segment_changes('segment1', segment1, '1470947453877') - synchronizer.fetch_splits + synchronizer.fetch_splits(0) expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.once end + it 'fetch_splits - ' do + sync = subject.new(repositories, api_key, config, sdk_blocker, parameters) + stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + .to_return(status: 200, body: + '{ + "splits": [], + "since": -1, + "till": 1506703262918 + }') + + stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918') + .to_return(status: 200, body: + '{ + "splits": [], + "since": 1506703262918, + "till": 1506703262918 + }') + + stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918&till=1506703262920') + .to_return(status: 200, body: + '{ + "splits": [], + "since": 1506703262918, + "till": 1506703262921 + }') + + sync.fetch_splits(1_506_703_262_920) + + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.once + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918')).to have_been_made.times(9) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918&till=1506703262920')).to have_been_made.once + end + it 'fetch_segment' do mock_segment_changes('segment3', segment3, '-1') diff --git a/spec/splitclient/split_config_spec.rb b/spec/splitclient/split_config_spec.rb index 97b675f2..8c5542fa 100644 --- a/spec/splitclient/split_config_spec.rb +++ b/spec/splitclient/split_config_spec.rb @@ -31,7 +31,7 @@ expect(configs.ip_addresses_enabled).to eq default_ip expect(configs.machine_name).to eq SplitIoClient::SplitConfig.machine_hostname(default_ip, nil, :redis) expect(configs.machine_ip).to eq SplitIoClient::SplitConfig.machine_ip(default_ip, nil, :redis) - expect(configs.on_demand_fetch_retry_delay_ms).to eq SplitIoClient::SplitConfig.default_on_demand_fetch_retry_delay_ms + expect(configs.on_demand_fetch_retry_delay_seconds).to eq SplitIoClient::SplitConfig.default_on_demand_fetch_retry_delay_seconds expect(configs.on_demand_fetch_max_retries).to eq SplitIoClient::SplitConfig.default_on_demand_fetch_max_retries end diff --git a/spec/sse/event_source/back_off_spec.rb b/spec/sse/event_source/back_off_spec.rb index 303a0ac6..3bac2590 100644 --- a/spec/sse/event_source/back_off_spec.rb +++ b/spec/sse/event_source/back_off_spec.rb @@ -9,7 +9,7 @@ let(:log) { StringIO.new } it 'get intervals and reset attemps' do - back_off = subject.new(1) + back_off = subject.new(1, 0, 5) firts_interval = back_off.interval expect(firts_interval).to eq(0) @@ -27,7 +27,7 @@ it 'with custom config' do streaming_reconnect_back_off_base = 5 - back_off = subject.new(streaming_reconnect_back_off_base) + back_off = subject.new(streaming_reconnect_back_off_base, 0, 30) firts_interval = back_off.interval expect(firts_interval).to eq(0) @@ -42,4 +42,34 @@ reset_interval = back_off.interval expect(reset_interval).to eq(0) end + + it 'with max' do + streaming_reconnect_back_off_base = 5 + back_off = subject.new(streaming_reconnect_back_off_base, 0, 30) + + firts_interval = back_off.interval + expect(firts_interval).to eq(0) + + second_interval = back_off.interval + expect(second_interval).to eq(10) + + third_interval = back_off.interval + expect(third_interval).to eq(20) + + third_interval = back_off.interval + expect(third_interval).to eq(30) + + third_interval = back_off.interval + expect(third_interval).to eq(30) + + third_interval = back_off.interval + expect(third_interval).to eq(30) + + third_interval = back_off.interval + expect(third_interval).to eq(30) + + back_off.reset + reset_interval = back_off.interval + expect(reset_interval).to eq(0) + end end diff --git a/spec/sse/sse_handler_spec.rb b/spec/sse/sse_handler_spec.rb index 75dac878..41fd4a5d 100644 --- a/spec/sse/sse_handler_spec.rb +++ b/spec/sse/sse_handler_spec.rb @@ -62,7 +62,7 @@ mock_segment_changes('segment2', segment2, '1470947453878') mock_segment_changes('segment3', segment3, '-1') - synchronizer.fetch_splits + synchronizer.fetch_splits(0) end context 'SPLIT UPDATE event' do diff --git a/spec/sse/workers/splits_worker_spec.rb b/spec/sse/workers/splits_worker_spec.rb index 3274fc41..bd499166 100644 --- a/spec/sse/workers/splits_worker_spec.rb +++ b/spec/sse/workers/splits_worker_spec.rb @@ -49,7 +49,8 @@ sleep(1) - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918')).to have_been_made.times(10) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.times(1) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918')).to have_been_made.at_least_times(2) end context 'add change number to queue' do From 2b7647a1418b1ab4808b15f95e6a9d437d2dc277 Mon Sep 17 00:00:00 2001 From: Mauro Sanz Date: Wed, 21 Jul 2021 15:47:50 -0300 Subject: [PATCH 4/6] segments retries implementation --- lib/splitclient-rb/engine/api/segments.rb | 1 + lib/splitclient-rb/engine/synchronizer.rb | 62 +++++++++++++-- .../sse/workers/segments_worker.rb | 7 +- spec/engine/synchronizer_spec.rb | 76 +++++++++++++++++-- spec/sse/sse_handler_spec.rb | 2 +- spec/sse/workers/segments_worker_spec.rb | 2 +- 6 files changed, 130 insertions(+), 20 deletions(-) diff --git a/lib/splitclient-rb/engine/api/segments.rb b/lib/splitclient-rb/engine/api/segments.rb index 0c16adc7..7f4a2f8d 100644 --- a/lib/splitclient-rb/engine/api/segments.rb +++ b/lib/splitclient-rb/engine/api/segments.rb @@ -16,6 +16,7 @@ def fetch_segments_by_names(names, fetch_options = { cache_control_headers: fals names.each do |name| since = @segments_repository.get_change_number(name) + loop do segment = fetch_segment_changes(name, since, fetch_options) @segments_repository.add_to_segment(segment) diff --git a/lib/splitclient-rb/engine/synchronizer.rb b/lib/splitclient-rb/engine/synchronizer.rb index ac4df696..1e399073 100644 --- a/lib/splitclient-rb/engine/synchronizer.rb +++ b/lib/splitclient-rb/engine/synchronizer.rb @@ -86,21 +86,69 @@ def fetch_splits(target_change_number) if result[:success] @segment_fetcher.fetch_segments_if_not_exists(result[:segment_names], true) unless result[:segment_names].empty? - @config.logger.debug("Refresh completed bypassing the CDN in #{attempts} attempts.") + @config.logger.debug("Refresh completed bypassing the CDN in #{attempts} attempts.") if @config.debug_enabled else - @config.logger.debug("No changes fetched after #{attempts} attempts with CDN bypassed.") + @config.logger.debug("No changes fetched after #{attempts} attempts with CDN bypassed.") if @config.debug_enabled end rescue StandardError => error @config.log_found_exception(__method__.to_s, error) end - def fetch_segment(name) + def fetch_segment(name, target_change_number) + return if target_change_number <= @segments_repository.get_change_number(name).to_i + fetch_options = { cache_control_headers: true, till: nil } - @segment_fetcher.fetch_segment(name, fetch_options) + result = attempt_segment_sync(name, + target_change_number, + fetch_options, + @config.on_demand_fetch_max_retries, + @config.on_demand_fetch_retry_delay_seconds, + false) + + attempts = @config.on_demand_fetch_max_retries - result[:remaining_attempts] + if result[:success] + @config.logger.debug("Segment #{name} refresh completed in #{attempts} attempts.") if @config.debug_enabled + + return + end + + fetch_options = { cache_control_headers: true, till: target_change_number } + result = attempt_segment_sync(name, + target_change_number, + fetch_options, + ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES, + nil, + true) + + attempts = @config.on_demand_fetch_max_retries - result[:remaining_attempts] + if result[:success] + @config.logger.debug("Segment #{name} refresh completed bypassing the CDN in #{attempts} attempts.") if @config.debug_enabled + else + @config.logger.debug("No changes fetched for segment #{name} after #{attempts} attempts with CDN bypassed.") if @config.debug_enabled + end + rescue StandardError => error + @config.log_found_exception(__method__.to_s, error) end private + def attempt_segment_sync(name, target_cn, fetch_options, max_retries, retry_delay_seconds, with_backoff) + remaining_attempts = max_retries + backoff = SSE::EventSource::BackOff.new(ON_DEMAND_FETCH_BACKOFF_BASE_SECONDS, 0, ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_SECONDS) if with_backoff + + loop do + remaining_attempts -= 1 + + @segment_fetcher.fetch_segment(name, fetch_options) + + return sync_result(true, remaining_attempts) if target_cn <= @segments_repository.get_change_number(name).to_i + return sync_result(false, remaining_attempts) if remaining_attempts <= 0 + + delay = with_backoff ? backoff.interval : retry_delay_seconds + sleep(delay) + end + end + def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_seconds, with_backoff) remaining_attempts = max_retries backoff = SSE::EventSource::BackOff.new(ON_DEMAND_FETCH_BACKOFF_BASE_SECONDS, 0, ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_SECONDS) if with_backoff @@ -110,8 +158,8 @@ def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_secon segment_names = @split_fetcher.fetch_splits(fetch_options) - return split_sync_result(true, remaining_attempts, segment_names) if target_cn <= @splits_repository.get_change_number - return split_sync_result(false, remaining_attempts, segment_names) if remaining_attempts <= 0 + return sync_result(true, remaining_attempts, segment_names) if target_cn <= @splits_repository.get_change_number + return sync_result(false, remaining_attempts, segment_names) if remaining_attempts <= 0 delay = with_backoff ? backoff.interval : retry_delay_seconds sleep(delay) @@ -141,7 +189,7 @@ def start_telemetry_sync_task Telemetry::SyncTask.new(@config, @telemetry_synchronizer).call end - def split_sync_result(success, remaining_attempts, segment_names) + def sync_result(success, remaining_attempts, segment_names = nil) { success: success, remaining_attempts: remaining_attempts, segment_names: segment_names } end end diff --git a/lib/splitclient-rb/sse/workers/segments_worker.rb b/lib/splitclient-rb/sse/workers/segments_worker.rb index d078a356..0a288ecc 100644 --- a/lib/splitclient-rb/sse/workers/segments_worker.rb +++ b/lib/splitclient-rb/sse/workers/segments_worker.rb @@ -3,7 +3,6 @@ module SplitIoClient module SSE module Workers - MAX_RETRIES_ALLOWED = 10 class SegmentsWorker def initialize(synchronizer, config, segments_repository) @synchronizer = synchronizer @@ -52,11 +51,7 @@ def perform cn = item[:change_number] @config.logger.debug("SegmentsWorker change_number dequeue #{segment_name}, #{cn}") - attempt = 0 - while cn > @segments_repository.get_change_number(segment_name).to_i && attempt <= MAX_RETRIES_ALLOWED - @synchronizer.fetch_segment(segment_name) - attempt += 1 - end + @synchronizer.fetch_segment(segment_name, cn) end end diff --git a/spec/engine/synchronizer_spec.rb b/spec/engine/synchronizer_spec.rb index f79ee117..87d4311a 100644 --- a/spec/engine/synchronizer_spec.rb +++ b/spec/engine/synchronizer_spec.rb @@ -96,8 +96,7 @@ expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.once end - it 'fetch_splits - ' do - sync = subject.new(repositories, api_key, config, sdk_blocker, parameters) + it 'fetch_splits - with CDN bypassed' do stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') .to_return(status: 200, body: '{ @@ -122,7 +121,7 @@ "till": 1506703262921 }') - sync.fetch_splits(1_506_703_262_920) + synchronizer.fetch_splits(1_506_703_262_920) expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.once expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918')).to have_been_made.times(9) @@ -130,10 +129,77 @@ end it 'fetch_segment' do - mock_segment_changes('segment3', segment3, '-1') + stub_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=-1') + .to_return(status: 200, body: + '{ + "name": "segment3", + "added": [], + "removed": [], + "since": -1, + "till": 111333 + }') + + stub_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=111333') + .to_return(status: 200, body: + '{ + "name": "segment3", + "added": [], + "removed": [], + "since": 111333, + "till": 111333 + }') + + synchronizer.fetch_segment('segment3', 111_222) + expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=-1')).to have_been_made.once + expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=111333')).to have_been_made.once + end + + it 'fetch_segment - with CDN bypassed' do + stub_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=-1') + .to_return(status: 200, body: + '{ + "name": "segment3", + "added": [], + "removed": [], + "since": -1, + "till": 111333 + }') + + stub_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=111333') + .to_return(status: 200, body: + '{ + "name": "segment3", + "added": [], + "removed": [], + "since": 111333, + "till": 111333 + }') + + stub_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=111333&till=111555') + .to_return(status: 200, body: + '{ + "name": "segment3", + "added": [], + "removed": [], + "since": 111555, + "till": 111555 + }') + + stub_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=111555&till=111555') + .to_return(status: 200, body: + '{ + "name": "segment3", + "added": [], + "removed": [], + "since": 111555, + "till": 111555 + }') - synchronizer.fetch_segment('segment3') + synchronizer.fetch_segment('segment3', 111_555) expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=-1')).to have_been_made.once + expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=111333')).to have_been_made.times(10) + expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=111333&till=111555')).to have_been_made.once + expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=111555&till=111555')).to have_been_made.once end end diff --git a/spec/sse/sse_handler_spec.rb b/spec/sse/sse_handler_spec.rb index 41fd4a5d..f5943138 100644 --- a/spec/sse/sse_handler_spec.rb +++ b/spec/sse/sse_handler_spec.rb @@ -212,7 +212,7 @@ expect(action_event).to eq(SplitIoClient::Constants::PUSH_CONNECTED) expect(sse_handler.sse_client.connected?).to eq(true) - expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=1470947453877')).to have_been_made.times(12) + expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=1470947453877')).to have_been_made.times(11) sse_handler.sse_client.close diff --git a/spec/sse/workers/segments_worker_spec.rb b/spec/sse/workers/segments_worker_spec.rb index 7d67f0c9..e0b11ba6 100644 --- a/spec/sse/workers/segments_worker_spec.rb +++ b/spec/sse/workers/segments_worker_spec.rb @@ -68,7 +68,7 @@ sleep(1) - expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=1470947453877')).to have_been_made.times(12) + expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=1470947453877')).to have_been_made.times(11) end it 'must not trigger fetch' do From cd683aacf25a0cc66521d880e0da1ac627409352 Mon Sep 17 00:00:00 2001 From: Mauro Sanz Date: Wed, 21 Jul 2021 16:47:02 -0300 Subject: [PATCH 5/6] pr feedback --- lib/splitclient-rb.rb | 4 +-- lib/splitclient-rb/engine/back_off.rb | 26 +++++++++++++++++ lib/splitclient-rb/engine/push_manager.rb | 2 +- lib/splitclient-rb/engine/synchronizer.rb | 4 +-- .../sse/event_source/back_off.rb | 28 ------------------- spec/sse/event_source/back_off_spec.rb | 4 +-- 6 files changed, 33 insertions(+), 35 deletions(-) create mode 100644 lib/splitclient-rb/engine/back_off.rb delete mode 100644 lib/splitclient-rb/sse/event_source/back_off.rb diff --git a/lib/splitclient-rb.rb b/lib/splitclient-rb.rb index d9657280..a184a173 100644 --- a/lib/splitclient-rb.rb +++ b/lib/splitclient-rb.rb @@ -85,13 +85,13 @@ require 'splitclient-rb/engine/models/label' require 'splitclient-rb/engine/models/treatment' require 'splitclient-rb/engine/auth_api_client' +require 'splitclient-rb/engine/back_off' require 'splitclient-rb/engine/push_manager' require 'splitclient-rb/engine/sync_manager' require 'splitclient-rb/engine/synchronizer' require 'splitclient-rb/utilitites' -# SSE -require 'splitclient-rb/sse/event_source/back_off' +# SSE require 'splitclient-rb/sse/event_source/client' require 'splitclient-rb/sse/event_source/event_parser' require 'splitclient-rb/sse/event_source/event_types' diff --git a/lib/splitclient-rb/engine/back_off.rb b/lib/splitclient-rb/engine/back_off.rb new file mode 100644 index 00000000..31097a09 --- /dev/null +++ b/lib/splitclient-rb/engine/back_off.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: false + +module SplitIoClient + module Engine + BACKOFF_MAX_ALLOWED = 1.8 + class BackOff + def initialize(back_off_base, attempt = 0, max_allowed = BACKOFF_MAX_ALLOWED) + @attempt = attempt + @back_off_base = back_off_base + @max_allowed = max_allowed + end + + def interval + interval = 0 + interval = (@back_off_base * (2**@attempt)) if @attempt.positive? + @attempt += 1 + + interval >= @max_allowed ? @max_allowed : interval + end + + def reset + @attempt = 0 + end + end + end +end diff --git a/lib/splitclient-rb/engine/push_manager.rb b/lib/splitclient-rb/engine/push_manager.rb index 61f9eed3..f30aa46e 100644 --- a/lib/splitclient-rb/engine/push_manager.rb +++ b/lib/splitclient-rb/engine/push_manager.rb @@ -8,7 +8,7 @@ def initialize(config, sse_handler, api_key, telemetry_runtime_producer) @sse_handler = sse_handler @auth_api_client = AuthApiClient.new(@config, telemetry_runtime_producer) @api_key = api_key - @back_off = SplitIoClient::SSE::EventSource::BackOff.new(@config.auth_retry_back_off_base, 1) + @back_off = Engine::BackOff.new(@config.auth_retry_back_off_base, 1) @telemetry_runtime_producer = telemetry_runtime_producer end diff --git a/lib/splitclient-rb/engine/synchronizer.rb b/lib/splitclient-rb/engine/synchronizer.rb index 1e399073..f7f4d11e 100644 --- a/lib/splitclient-rb/engine/synchronizer.rb +++ b/lib/splitclient-rb/engine/synchronizer.rb @@ -134,7 +134,7 @@ def fetch_segment(name, target_change_number) def attempt_segment_sync(name, target_cn, fetch_options, max_retries, retry_delay_seconds, with_backoff) remaining_attempts = max_retries - backoff = SSE::EventSource::BackOff.new(ON_DEMAND_FETCH_BACKOFF_BASE_SECONDS, 0, ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_SECONDS) if with_backoff + backoff = Engine::BackOff.new(ON_DEMAND_FETCH_BACKOFF_BASE_SECONDS, 0, ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_SECONDS) if with_backoff loop do remaining_attempts -= 1 @@ -151,7 +151,7 @@ def attempt_segment_sync(name, target_cn, fetch_options, max_retries, retry_dela def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_seconds, with_backoff) remaining_attempts = max_retries - backoff = SSE::EventSource::BackOff.new(ON_DEMAND_FETCH_BACKOFF_BASE_SECONDS, 0, ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_SECONDS) if with_backoff + backoff = Engine::BackOff.new(ON_DEMAND_FETCH_BACKOFF_BASE_SECONDS, 0, ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_SECONDS) if with_backoff loop do remaining_attempts -= 1 diff --git a/lib/splitclient-rb/sse/event_source/back_off.rb b/lib/splitclient-rb/sse/event_source/back_off.rb deleted file mode 100644 index ea21fc85..00000000 --- a/lib/splitclient-rb/sse/event_source/back_off.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: false - -module SplitIoClient - module SSE - module EventSource - BACKOFF_MAX_ALLOWED = 1.8 - class BackOff - def initialize(back_off_base, attempt = 0, max_allowed = BACKOFF_MAX_ALLOWED) - @attempt = attempt - @back_off_base = back_off_base - @max_allowed = max_allowed - end - - def interval - interval = 0 - interval = (@back_off_base * (2**@attempt)) if @attempt.positive? - @attempt += 1 - - interval >= @max_allowed ? @max_allowed : interval - end - - def reset - @attempt = 0 - end - end - end - end -end diff --git a/spec/sse/event_source/back_off_spec.rb b/spec/sse/event_source/back_off_spec.rb index 3bac2590..b63268c4 100644 --- a/spec/sse/event_source/back_off_spec.rb +++ b/spec/sse/event_source/back_off_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' require 'http_server_mock' -describe SplitIoClient::SSE::EventSource::BackOff do - subject { SplitIoClient::SSE::EventSource::BackOff } +describe SplitIoClient::Engine::BackOff do + subject { SplitIoClient::Engine::BackOff } let(:log) { StringIO.new } From 5d559dd1812cea2f2bbf2d030c23afa899e845f9 Mon Sep 17 00:00:00 2001 From: Mauro Sanz Date: Mon, 26 Jul 2021 15:48:10 -0300 Subject: [PATCH 6/6] polishing --- CHANGES.txt | 3 +++ lib/splitclient-rb/engine/synchronizer.rb | 2 +- lib/splitclient-rb/version.rb | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 2022cdd6..0e9633e0 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,8 @@ CHANGES +7.3.1 (Jul 26, 2021) +- Updated the synchronization flow to be more reliable in the event of an edge case generating delay in cache purge propagation, keeping the SDK cache properly synced. + 7.3.0 (Jul 12, 2021) - Updated SDK telemetry storage, metrics and updater to be more effective and send less often. - Fixed high cpu usage when api key is wrong. diff --git a/lib/splitclient-rb/engine/synchronizer.rb b/lib/splitclient-rb/engine/synchronizer.rb index f7f4d11e..bbaae13a 100644 --- a/lib/splitclient-rb/engine/synchronizer.rb +++ b/lib/splitclient-rb/engine/synchronizer.rb @@ -82,7 +82,7 @@ def fetch_splits(target_change_number) nil, true) - attempts = @config.on_demand_fetch_max_retries - result[:remaining_attempts] + attempts = ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES - result[:remaining_attempts] if result[:success] @segment_fetcher.fetch_segments_if_not_exists(result[:segment_names], true) unless result[:segment_names].empty? diff --git a/lib/splitclient-rb/version.rb b/lib/splitclient-rb/version.rb index b204d940..0e1cd8ae 100644 --- a/lib/splitclient-rb/version.rb +++ b/lib/splitclient-rb/version.rb @@ -1,3 +1,3 @@ module SplitIoClient - VERSION = '7.3.0' + VERSION = '7.3.1' end