splitclient-rb 7.3.0.pre.rc3 → 7.3.2.pre.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85d3602c1b6aa514393f464c6032b557de0419e6ba321d3bdf0c3835a55b1db0
4
- data.tar.gz: 7ae53a7b87f13ce2a975d71be6dd4bb8a615395d2f2f66b04eb8058573ac10fd
3
+ metadata.gz: 03f80e502a07426668e103fece089d2178a8f79b6cd7b99d79fd8832cd75fb41
4
+ data.tar.gz: 85d9a9d18a4a334581ffad67bdc39ce1d07c10f1d9a6e043f321ceeb9fc33e43
5
5
  SHA512:
6
- metadata.gz: 803c1e761ff1c13a501f47b56641b854efc079ef8732c1a24793b03b691fb1bb9e5fb2a9eddedc819f1458e314dcd37991311f730c2aaf7751ffa7e4c3190141
7
- data.tar.gz: 849bfd49993b52ddb222f9c85157088181182539235e6ce36eb74b3a2f3823bc1e4b4b7455d306d08b81678bb60112483e5813e7dd8879b19ca1a19548ac1d44
6
+ metadata.gz: 43e4f5b131a63d2c0af3475a49e018d8da1bade5f09aead17025f0cf748612809521e85243dfc7c9c712ba5d8ec31b54117acb14c043c8f6d93650f4a3d9db35
7
+ data.tar.gz: a1abf9cccb7833173d7e071c70ca216db0476f2fc5e9ae23f4d402a706fd65cfe2712b04771fba19f1bc00b97d3bb07b0f3532279ed66f610c6251715197785c
@@ -0,0 +1,78 @@
1
+ on:
2
+ push:
3
+ branches:
4
+ - master
5
+ pull_request:
6
+ branches:
7
+ - master
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ services:
13
+ redis:
14
+ image: redis
15
+ ports:
16
+ - 6379:6379
17
+ steps:
18
+ - name: Checkout code
19
+ uses: actions/checkout@v2
20
+ with:
21
+ fetch-depth: 0
22
+
23
+ - name: Set up Ruby
24
+ uses: ruby/setup-ruby@477b21f02be01bcb8030d50f37cfec92bfa615b6
25
+ with:
26
+ ruby-version: 2.5
27
+
28
+ - name: Install dependencies
29
+ run: bundle install
30
+
31
+ - name: Run tests
32
+ run: bundle exec rake
33
+
34
+ - name: Fix code coverage paths
35
+ working-directory: ./coverage
36
+ run: |
37
+ sed -i 's@'$GITHUB_WORKSPACE'@/github/workspace/@g' .resultset.json
38
+ ruby -rjson -e 'sqube = JSON.load(File.read(".resultset.json"))["RSpec"]["coverage"].transform_values {|lines| lines["lines"]}; total = { "RSpec" => { "coverage" => sqube, "timestamp" => Time.now.to_i }}; puts JSON.dump(total)' > .resultset.sonarqube.json
39
+
40
+
41
+ - name: SonarQube Scan (Push)
42
+ if: github.event_name == 'push'
43
+ uses: SonarSource/sonarcloud-github-action@v1.5
44
+ env:
45
+ SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
46
+ with:
47
+ projectBaseDir: .
48
+ args: >
49
+ -Dsonar.host.url=${{ secrets.SONARQUBE_HOST }}
50
+ -Dsonar.projectName=${{ github.event.repository.name }}
51
+ -Dsonar.projectKey=${{ github.event.repository.name }}
52
+ -Dsonar.ruby.coverage.reportPaths=coverage/.resultset.sonarqube.json
53
+ -Dsonar.c.file.suffixes=-
54
+ -Dsonar.cpp.file.suffixes=-
55
+ -Dsonar.objc.file.suffixes=-
56
+ -Dsonar.links.ci="https://github.com/splitio/${{ github.event.repository.name }}/actions"
57
+ -Dsonar.links.scm="https://github.com/splitio/${{ github.event.repository.name }}"
58
+
59
+ - name: SonarQube Scan (Pull Request)
60
+ if: github.event_name == 'pull_request'
61
+ uses: SonarSource/sonarcloud-github-action@v1.5
62
+ env:
63
+ SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
64
+ with:
65
+ projectBaseDir: .
66
+ args: >
67
+ -Dsonar.host.url=${{ secrets.SONARQUBE_HOST }}
68
+ -Dsonar.projectName=${{ github.event.repository.name }}
69
+ -Dsonar.projectKey=${{ github.event.repository.name }}
70
+ -Dsonar.ruby.coverage.reportPaths=coverage/.resultset.sonarqube.json
71
+ -Dsonar.c.file.suffixes=-
72
+ -Dsonar.cpp.file.suffixes=-
73
+ -Dsonar.objc.file.suffixes=-
74
+ -Dsonar.links.ci="https://github.com/splitio/${{ github.event.repository.name }}/actions"
75
+ -Dsonar.links.scm="https://github.com/splitio/${{ github.event.repository.name }}"
76
+ -Dsonar.pullrequest.key=${{ github.event.pull_request.number }}
77
+ -Dsonar.pullrequest.branch=${{ github.event.pull_request.head.ref }}
78
+ -Dsonar.pullrequest.base=${{ github.event.pull_request.base.ref }}
data/.rubocop.yml CHANGED
@@ -31,6 +31,7 @@ Metrics/LineLength:
31
31
  - spec/engine/sync_manager_spec.rb
32
32
  - spec/engine/auth_api_client_spec.rb
33
33
  - spec/telemetry/synchronizer_spec.rb
34
+ - spec/splitclient/split_config_spec.rb
34
35
 
35
36
  Style/BracesAroundHashParameters:
36
37
  Exclude:
@@ -62,3 +63,4 @@ AllCops:
62
63
  - lib/splitclient-rb/engine/models/**/*
63
64
  - lib/splitclient-rb/engine/parser/**/*
64
65
  - spec/telemetry/synchronizer_spec.rb
66
+ - lib/splitclient-rb/engine/synchronizer.rb
data/CHANGES.txt CHANGED
@@ -1,5 +1,12 @@
1
1
  CHANGES
2
2
 
3
+ 7.3.1 (Jul 26, 2021)
4
+ - 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.
5
+
6
+ 7.3.0 (Jul 12, 2021)
7
+ - Updated SDK telemetry storage, metrics and updater to be more effective and send less often.
8
+ - Fixed high cpu usage when api key is wrong.
9
+
3
10
  7.2.3 (Feb 24, 2021)
4
11
  - Fixed missing segment fetch after an SPLIT_UPDATE.
5
12
  - Updated streaming logic to support multiregion.
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright © 2020 Split Software, Inc.
1
+ Copyright © 2021 Split Software, Inc.
2
2
 
3
3
  Licensed under the Apache License, Version 2.0 (the "License");
4
4
  you may not use this file except in compliance with the License.
data/README.md CHANGED
@@ -63,7 +63,7 @@ Split has built and maintains SDKs for:
63
63
  * Java [Github](https://github.com/splitio/java-client) [Docs](https://help.split.io/hc/en-us/articles/360020405151-Java-SDK)
64
64
  * Javascript [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK)
65
65
  * Node [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK)
66
- * .NET [Github](https://github.com/splitio/.net-core-client) [Docs](https://help.split.io/hc/en-us/articles/360020240172--NET-SDK)
66
+ * .NET [Github](https://github.com/splitio/dotnet-client) [Docs](https://help.split.io/hc/en-us/articles/360020240172--NET-SDK)
67
67
  * Ruby [Github](https://github.com/splitio/ruby-client) [Docs](https://help.split.io/hc/en-us/articles/360020673251-Ruby-SDK)
68
68
  * PHP [Github](https://github.com/splitio/php-client) [Docs](https://help.split.io/hc/en-us/articles/360020350372-PHP-SDK)
69
69
  * Python [Github](https://github.com/splitio/python-client) [Docs](https://help.split.io/hc/en-us/articles/360020359652-Python-SDK)
@@ -4,11 +4,10 @@ module SplitIoClient
4
4
  class SegmentFetcher
5
5
  attr_reader :segments_repository
6
6
 
7
- def initialize(segments_repository, api_key, config, sdk_blocker, telemetry_runtime_producer)
7
+ def initialize(segments_repository, api_key, config, telemetry_runtime_producer)
8
8
  @segments_repository = segments_repository
9
9
  @api_key = api_key
10
10
  @config = config
11
- @sdk_blocker = sdk_blocker
12
11
  @semaphore = Mutex.new
13
12
  @telemetry_runtime_producer = telemetry_runtime_producer
14
13
  end
@@ -30,16 +29,19 @@ module SplitIoClient
30
29
  def fetch_segments_if_not_exists(names, cache_control_headers = false)
31
30
  names.each do |name|
32
31
  change_number = @segments_repository.get_change_number(name)
33
-
34
- fetch_segment(name, cache_control_headers) if change_number == -1
32
+
33
+ if change_number == -1
34
+ fetch_options = { cache_control_headers: cache_control_headers, till: nil }
35
+ fetch_segment(name, fetch_options) if change_number == -1
36
+ end
35
37
  end
36
38
  rescue StandardError => error
37
39
  @config.log_found_exception(__method__.to_s, error)
38
40
  end
39
41
 
40
- def fetch_segment(name, cache_control_headers = false)
42
+ def fetch_segment(name, fetch_options = { cache_control_headers: false, till: nil })
41
43
  @semaphore.synchronize do
42
- segments_api.fetch_segments_by_names([name], cache_control_headers)
44
+ segments_api.fetch_segments_by_names([name], fetch_options)
43
45
  end
44
46
  rescue StandardError => error
45
47
  @config.log_found_exception(__method__.to_s, error)
@@ -49,11 +51,11 @@ module SplitIoClient
49
51
  @semaphore.synchronize do
50
52
  segments_api.fetch_segments_by_names(@segments_repository.used_segment_names)
51
53
 
52
- @sdk_blocker.segments_ready!
53
- @sdk_blocker.sdk_internal_ready
54
+ true
54
55
  end
55
56
  rescue StandardError => error
56
57
  @config.log_found_exception(__method__.to_s, error)
58
+ false
57
59
  end
58
60
 
59
61
  def stop_segments_thread
@@ -67,11 +69,6 @@ module SplitIoClient
67
69
  @config.logger.info('Starting segments fetcher service') if @config.debug_enabled
68
70
 
69
71
  loop do
70
- unless @sdk_blocker.splits_repository.ready?
71
- sleep 0.2
72
- next
73
- end
74
-
75
72
  fetch_segments
76
73
  @config.logger.debug("Segment names: #{@segments_repository.used_segment_names.to_a}") if @config.debug_enabled
77
74
 
@@ -4,11 +4,10 @@ module SplitIoClient
4
4
  class SplitFetcher
5
5
  attr_reader :splits_repository
6
6
 
7
- def initialize(splits_repository, api_key, config, sdk_blocker, telemetry_runtime_producer)
7
+ def initialize(splits_repository, api_key, config, telemetry_runtime_producer)
8
8
  @splits_repository = splits_repository
9
9
  @api_key = api_key
10
10
  @config = config
11
- @sdk_blocker = sdk_blocker
12
11
  @semaphore = Mutex.new
13
12
  @telemetry_runtime_producer = telemetry_runtime_producer
14
13
  end
@@ -27,9 +26,9 @@ module SplitIoClient
27
26
  end
28
27
  end
29
28
 
30
- def fetch_splits(cache_control_headers = false)
29
+ def fetch_splits(fetch_options = { cache_control_headers: false, till: nil })
31
30
  @semaphore.synchronize do
32
- data = splits_since(@splits_repository.get_change_number, cache_control_headers)
31
+ data = splits_since(@splits_repository.get_change_number, fetch_options)
33
32
 
34
33
  data[:splits] && data[:splits].each do |split|
35
34
  add_split_unless_archived(split)
@@ -40,13 +39,11 @@ module SplitIoClient
40
39
 
41
40
  @config.logger.debug("segments seen(#{data[:segment_names].length}): #{data[:segment_names].to_a}") if @config.debug_enabled
42
41
 
43
- @sdk_blocker.splits_ready!
44
-
45
- data[:segment_names]
42
+ { segment_names: data[:segment_names], success: true }
46
43
  end
47
44
  rescue StandardError => error
48
45
  @config.log_found_exception(__method__.to_s, error)
49
- []
46
+ { segment_names: [], success: false }
50
47
  end
51
48
 
52
49
  def stop_splits_thread
@@ -68,8 +65,8 @@ module SplitIoClient
68
65
  end
69
66
  end
70
67
 
71
- def splits_since(since, cache_control_headers = false)
72
- splits_api.since(since, cache_control_headers)
68
+ def splits_since(since, fetch_options = { cache_control_headers: false, till: nil })
69
+ splits_api.since(since, fetch_options)
73
70
  end
74
71
 
75
72
  def add_split_unless_archived(split)
@@ -7,10 +7,10 @@ module SplitIoClient
7
7
  require 'yaml'
8
8
  attr_reader :splits_repository
9
9
 
10
- def initialize(splits_repository, config, sdk_blocker = nil)
10
+ def initialize(splits_repository, config, status_manager = nil)
11
11
  @splits_repository = splits_repository
12
12
  @config = config
13
- @sdk_blocker = sdk_blocker
13
+ @status_manager = status_manager
14
14
  end
15
15
 
16
16
  def call
@@ -45,10 +45,7 @@ module SplitIoClient
45
45
  store_split(split)
46
46
  end
47
47
 
48
- if @sdk_blocker
49
- @sdk_blocker.splits_ready!
50
- @sdk_blocker.segments_ready!
51
- end
48
+ @status_manager.ready! if @status_manager
52
49
  rescue StandardError => error
53
50
  @config.logger.error('Error while parsing the split file. ' \
54
51
  'Check that the input file matches the expected format')
@@ -14,13 +14,13 @@ module SplitIoClient
14
14
  # @param api_key [String] the API key for your split account
15
15
  #
16
16
  # @return [SplitIoClient] split.io client instance
17
- def initialize(api_key, repositories, sdk_blocker, config, impressions_manager, telemetry_evaluation_producer)
17
+ def initialize(api_key, repositories, status_manager, config, impressions_manager, telemetry_evaluation_producer)
18
18
  @api_key = api_key
19
19
  @splits_repository = repositories[:splits]
20
20
  @segments_repository = repositories[:segments]
21
21
  @impressions_repository = repositories[:impressions]
22
22
  @events_repository = repositories[:events]
23
- @sdk_blocker = sdk_blocker
23
+ @status_manager = status_manager
24
24
  @destroyed = false
25
25
  @config = config
26
26
  @impressions_manager = impressions_manager
@@ -137,7 +137,7 @@ module SplitIoClient
137
137
  else
138
138
  {
139
139
  treatment: treatment_data[:treatment],
140
- config: treatment_data[:config]
140
+ config: treatment_data[:config],
141
141
  }
142
142
  end
143
143
  end
@@ -157,7 +157,7 @@ module SplitIoClient
157
157
  end
158
158
 
159
159
  def block_until_ready(time = nil)
160
- @sdk_blocker.block(time) if @sdk_blocker && !@sdk_blocker.ready?
160
+ @status_manager.wait_until_ready(time) if @status_manager
161
161
  end
162
162
 
163
163
  private
@@ -310,7 +310,7 @@ module SplitIoClient
310
310
  end
311
311
 
312
312
  def ready?
313
- return @sdk_blocker.ready? if @sdk_blocker
313
+ return @status_manager.ready? if @status_manager
314
314
  true
315
315
  end
316
316
 
@@ -11,13 +11,14 @@ module SplitIoClient
11
11
  @telemetry_runtime_producer = telemetry_runtime_producer
12
12
  end
13
13
 
14
- def fetch_segments_by_names(names, cache_control_headers = false)
14
+ def fetch_segments_by_names(names, fetch_options = { cache_control_headers: false, till: nil })
15
15
  return if names.nil? || names.empty?
16
16
 
17
17
  names.each do |name|
18
18
  since = @segments_repository.get_change_number(name)
19
+
19
20
  loop do
20
- segment = fetch_segment_changes(name, since, cache_control_headers)
21
+ segment = fetch_segment_changes(name, since, fetch_options)
21
22
  @segments_repository.add_to_segment(segment)
22
23
 
23
24
  @config.split_logger.log_if_debug("Segment #{name} fetched before: #{since}, \
@@ -32,9 +33,12 @@ module SplitIoClient
32
33
 
33
34
  private
34
35
 
35
- def fetch_segment_changes(name, since, cache_control_headers = false)
36
+ def fetch_segment_changes(name, since, fetch_options = { cache_control_headers: false, till: nil })
36
37
  start = Time.now
37
- response = get_api("#{@config.base_uri}/segmentChanges/#{name}", @api_key, { since: since }, cache_control_headers)
38
+
39
+ params = { since: since }
40
+ params[:till] = fetch_options[:till] unless fetch_options[:till].nil?
41
+ response = get_api("#{@config.base_uri}/segmentChanges/#{name}", @api_key, params, fetch_options[:cache_control_headers])
38
42
 
39
43
  if response.success?
40
44
  segment = JSON.parse(response.body, symbolize_names: true)
@@ -10,10 +10,12 @@ module SplitIoClient
10
10
  @telemetry_runtime_producer = telemetry_runtime_producer
11
11
  end
12
12
 
13
- def since(since, cache_control_headers = false)
13
+ def since(since, fetch_options = { cache_control_headers: false, till: nil })
14
14
  start = Time.now
15
-
16
- response = get_api("#{@config.base_uri}/splitChanges", @api_key, { since: since }, cache_control_headers)
15
+
16
+ params = { since: since }
17
+ params[:till] = fetch_options[:till] unless fetch_options[:till].nil?
18
+ response = get_api("#{@config.base_uri}/splitChanges", @api_key, params, fetch_options[:cache_control_headers])
17
19
  if response.success?
18
20
  result = splits_with_segment_names(response.body)
19
21
 
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: false
2
+
3
+ module SplitIoClient
4
+ module Engine
5
+ BACKOFF_MAX_ALLOWED = 1.8
6
+ class BackOff
7
+ def initialize(back_off_base, attempt = 0, max_allowed = BACKOFF_MAX_ALLOWED)
8
+ @attempt = attempt
9
+ @back_off_base = back_off_base
10
+ @max_allowed = max_allowed
11
+ end
12
+
13
+ def interval
14
+ interval = 0
15
+ interval = (@back_off_base * (2**@attempt)) if @attempt.positive?
16
+ @attempt += 1
17
+
18
+ interval >= @max_allowed ? @max_allowed : interval
19
+ end
20
+
21
+ def reset
22
+ @attempt = 0
23
+ end
24
+ end
25
+ end
26
+ end
@@ -21,8 +21,8 @@ module SplitIoClient
21
21
  @impression_counter.inc(split_name, impression_data[:m]) if optimized? && !redis?
22
22
 
23
23
  impression(impression_data, params[:attributes])
24
- rescue StandardError => error
25
- @config.log_found_exception(__method__.to_s, error)
24
+ rescue StandardError => e
25
+ @config.log_found_exception(__method__.to_s, e)
26
26
  end
27
27
 
28
28
  def track(impressions)
@@ -48,8 +48,8 @@ module SplitIoClient
48
48
  end
49
49
 
50
50
  record_stats(queued, dropped, dedupe)
51
- rescue StandardError => error
52
- @config.log_found_exception(__method__.to_s, error)
51
+ rescue StandardError => e
52
+ @config.log_found_exception(__method__.to_s, e)
53
53
  end
54
54
 
55
55
  private
@@ -8,7 +8,7 @@ module SplitIoClient
8
8
  @sse_handler = sse_handler
9
9
  @auth_api_client = AuthApiClient.new(@config, telemetry_runtime_producer)
10
10
  @api_key = api_key
11
- @back_off = SplitIoClient::SSE::EventSource::BackOff.new(@config.auth_retry_back_off_base, 1)
11
+ @back_off = Engine::BackOff.new(@config.auth_retry_back_off_base, 1)
12
12
  @telemetry_runtime_producer = telemetry_runtime_producer
13
13
  end
14
14
 
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Engine
5
+ class StatusManager
6
+ def initialize(config)
7
+ @config = config
8
+ @sdk_ready = Concurrent::CountDownLatch.new(1)
9
+ end
10
+
11
+ def ready?
12
+ return true if @config.consumer?
13
+
14
+ @sdk_ready.wait(0)
15
+ end
16
+
17
+ def ready!
18
+ return if ready?
19
+
20
+ @sdk_ready.count_down
21
+ @config.logger.info('SplitIO SDK is ready')
22
+ end
23
+
24
+ def wait_until_ready(seconds = nil)
25
+ return if @config.consumer?
26
+
27
+ timeout = seconds || @config.block_until_ready
28
+
29
+ raise SDKBlockerTimeoutExpiredException, 'SDK start up timeout expired' unless @sdk_ready.wait(timeout)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -12,8 +12,8 @@ module SplitIoClient
12
12
  config,
13
13
  synchronizer,
14
14
  telemetry_runtime_producer,
15
- sdk_blocker,
16
- telemetry_synchronizer
15
+ telemetry_synchronizer,
16
+ status_manager
17
17
  )
18
18
  @synchronizer = synchronizer
19
19
  notification_manager_keeper = SSE::NotificationManagerKeeper.new(config, telemetry_runtime_producer) do |manager|
@@ -33,56 +33,37 @@ module SplitIoClient
33
33
  @sse_connected = Concurrent::AtomicBoolean.new(false)
34
34
  @config = config
35
35
  @telemetry_runtime_producer = telemetry_runtime_producer
36
- @sdk_blocker = sdk_blocker
37
36
  @telemetry_synchronizer = telemetry_synchronizer
37
+ @status_manager = status_manager
38
38
  end
39
39
 
40
40
  def start
41
- if @config.streaming_enabled
42
- start_stream
43
- start_stream_forked if defined?(PhusionPassenger)
44
- elsif @config.standalone?
45
- start_poll
46
- end
41
+ @config.threads[:start_sdk] = Thread.new do
42
+ sleep(0.5) until @synchronizer.sync_all(false)
47
43
 
48
- synchronize_telemetry_config
49
- end
44
+ @status_manager.ready!
45
+ @telemetry_synchronizer.synchronize_config
46
+ @synchronizer.start_periodic_data_recording
47
+ connected = false
50
48
 
51
- private
52
-
53
- # Starts tasks if stream is enabled.
54
- def start_stream
55
- @config.logger.debug('Starting push mode ...')
56
- @synchronizer.sync_all
57
- @synchronizer.start_periodic_data_recording
58
-
59
- start_sse_connection_thread
60
- end
49
+ if @config.streaming_enabled
50
+ @config.logger.debug('Starting Straming mode ...')
51
+ connected = @push_manager.start_sse
61
52
 
62
- def start_poll
63
- @config.logger.debug('Starting polling mode ...')
64
- @synchronizer.start_periodic_fetch
65
- @synchronizer.start_periodic_data_recording
66
- record_telemetry(Telemetry::Domain::Constants::SYNC_MODE, SYNC_MODE_POLLING)
67
- rescue StandardError => e
68
- @config.logger.error("start_poll error : #{e.inspect}")
69
- end
53
+ if defined?(PhusionPassenger)
54
+ PhusionPassenger.on_event(:starting_worker_process) { |forked| sse_thread_forked if forked }
55
+ end
56
+ end
70
57
 
71
- # Starts thread which connect to sse and after that fetch splits and segments once.
72
- def start_sse_connection_thread
73
- @config.threads[:sync_manager_start_sse] = Thread.new do
74
- begin
75
- connected = @push_manager.start_sse
76
- @synchronizer.start_periodic_fetch unless connected
77
- rescue StandardError => e
78
- @config.logger.error("start_sse_connection_thread error : #{e.inspect}")
58
+ unless connected
59
+ @config.logger.debug('Starting polling mode ...')
60
+ @synchronizer.start_periodic_fetch
61
+ record_telemetry(Telemetry::Domain::Constants::SYNC_MODE, SYNC_MODE_POLLING)
79
62
  end
80
63
  end
81
64
  end
82
65
 
83
- def start_stream_forked
84
- PhusionPassenger.on_event(:starting_worker_process) { |forked| start_stream if forked }
85
- end
66
+ private
86
67
 
87
68
  def process_action(action)
88
69
  case action
@@ -165,16 +146,9 @@ module SplitIoClient
165
146
  @telemetry_runtime_producer.record_streaming_event(type, data)
166
147
  end
167
148
 
168
- def synchronize_telemetry_config
169
- @config.threads[:telemetry_config_sender] = Thread.new do
170
- begin
171
- @sdk_blocker.wait_unitil_internal_ready unless @config.consumer?
172
- @telemetry_synchronizer.synchronize_config
173
- rescue SplitIoClient::SDKShutdownException
174
- @telemetry_synchronizer.synchronize_config
175
- @config.logger.info('Posting Telemetry config due to shutdown')
176
- end
177
- end
149
+ def sse_thread_forked
150
+ connected = @push_manager.start_sse
151
+ @synchronizer.start_periodic_fetch unless connected
178
152
  end
179
153
  end
180
154
  end
@@ -6,13 +6,14 @@ module SplitIoClient
6
6
  include SplitIoClient::Cache::Fetchers
7
7
  include SplitIoClient::Cache::Senders
8
8
 
9
- FORCE_CACHE_CONTROL_HEADERS = true
9
+ ON_DEMAND_FETCH_BACKOFF_BASE_SECONDS = 10
10
+ ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_SECONDS = 60
11
+ ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES = 10
10
12
 
11
13
  def initialize(
12
14
  repositories,
13
15
  api_key,
14
16
  config,
15
- sdk_blocker,
16
17
  params
17
18
  )
18
19
  @splits_repository = repositories[:splits]
@@ -21,7 +22,6 @@ module SplitIoClient
21
22
  @events_repository = repositories[:events]
22
23
  @api_key = api_key
23
24
  @config = config
24
- @sdk_blocker = sdk_blocker
25
25
  @split_fetcher = params[:split_fetcher]
26
26
  @segment_fetcher = params[:segment_fetcher]
27
27
  @impressions_api = SplitIoClient::Api::Impressions.new(@api_key, @config, params[:telemetry_runtime_producer])
@@ -29,12 +29,16 @@ module SplitIoClient
29
29
  @telemetry_synchronizer = params[:telemetry_synchronizer]
30
30
  end
31
31
 
32
- def sync_all
32
+ def sync_all(asynchronous = true)
33
+ unless asynchronous
34
+ return sync_splits_and_segments
35
+ end
36
+
33
37
  @config.threads[:sync_all_thread] = Thread.new do
34
- @config.logger.debug('Synchronizing Splits and Segments ...') if @config.debug_enabled
35
- @split_fetcher.fetch_splits
36
- @segment_fetcher.fetch_segments
38
+ sync_splits_and_segments
37
39
  end
40
+
41
+ true
38
42
  end
39
43
 
40
44
  def start_periodic_data_recording
@@ -54,19 +58,114 @@ module SplitIoClient
54
58
  @segment_fetcher.stop_segments_thread
55
59
  end
56
60
 
57
- def fetch_splits
58
- segment_names = @split_fetcher.fetch_splits(FORCE_CACHE_CONTROL_HEADERS)
59
- @segment_fetcher.fetch_segments_if_not_exists(segment_names, FORCE_CACHE_CONTROL_HEADERS) unless segment_names.empty?
61
+ def fetch_splits(target_change_number)
62
+ return if target_change_number <= @splits_repository.get_change_number.to_i
63
+
64
+ fetch_options = { cache_control_headers: true, till: nil }
65
+
66
+ result = attempt_splits_sync(target_change_number,
67
+ fetch_options,
68
+ @config.on_demand_fetch_max_retries,
69
+ @config.on_demand_fetch_retry_delay_seconds,
70
+ false)
71
+
72
+ attempts = @config.on_demand_fetch_max_retries - result[:remaining_attempts]
73
+ if result[:success]
74
+ @segment_fetcher.fetch_segments_if_not_exists(result[:segment_names], true) unless result[:segment_names].empty?
75
+ @config.logger.debug("Refresh completed in #{attempts} attempts.") if @config.debug_enabled
76
+
77
+ return
78
+ end
79
+
80
+ fetch_options[:till] = target_change_number
81
+ result = attempt_splits_sync(target_change_number,
82
+ fetch_options,
83
+ ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES,
84
+ nil,
85
+ true)
86
+
87
+ attempts = ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES - result[:remaining_attempts]
88
+
89
+ if result[:success]
90
+ @segment_fetcher.fetch_segments_if_not_exists(result[:segment_names], true) unless result[:segment_names].empty?
91
+ @config.logger.debug("Refresh completed bypassing the CDN in #{attempts} attempts.") if @config.debug_enabled
92
+ else
93
+ @config.logger.debug("No changes fetched after #{attempts} attempts with CDN bypassed.") if @config.debug_enabled
94
+ end
95
+ rescue StandardError => error
96
+ @config.log_found_exception(__method__.to_s, error)
60
97
  end
61
98
 
62
- def fetch_segment(name)
63
- @segment_fetcher.fetch_segment(name, FORCE_CACHE_CONTROL_HEADERS)
99
+ def fetch_segment(name, target_change_number)
100
+ return if target_change_number <= @segments_repository.get_change_number(name).to_i
101
+
102
+ fetch_options = { cache_control_headers: true, till: nil }
103
+ result = attempt_segment_sync(name,
104
+ target_change_number,
105
+ fetch_options,
106
+ @config.on_demand_fetch_max_retries,
107
+ @config.on_demand_fetch_retry_delay_seconds,
108
+ false)
109
+
110
+ attempts = @config.on_demand_fetch_max_retries - result[:remaining_attempts]
111
+ if result[:success]
112
+ @config.logger.debug("Segment #{name} refresh completed in #{attempts} attempts.") if @config.debug_enabled
113
+
114
+ return
115
+ end
116
+
117
+ fetch_options = { cache_control_headers: true, till: target_change_number }
118
+ result = attempt_segment_sync(name,
119
+ target_change_number,
120
+ fetch_options,
121
+ ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES,
122
+ nil,
123
+ true)
124
+
125
+ attempts = @config.on_demand_fetch_max_retries - result[:remaining_attempts]
126
+ if result[:success]
127
+ @config.logger.debug("Segment #{name} refresh completed bypassing the CDN in #{attempts} attempts.") if @config.debug_enabled
128
+ else
129
+ @config.logger.debug("No changes fetched for segment #{name} after #{attempts} attempts with CDN bypassed.") if @config.debug_enabled
130
+ end
131
+ rescue StandardError => error
132
+ @config.log_found_exception(__method__.to_s, error)
64
133
  end
65
134
 
66
135
  private
67
136
 
68
- def fetch_segments
69
- @segment_fetcher.fetch_segments
137
+ def attempt_segment_sync(name, target_cn, fetch_options, max_retries, retry_delay_seconds, with_backoff)
138
+ remaining_attempts = max_retries
139
+ backoff = Engine::BackOff.new(ON_DEMAND_FETCH_BACKOFF_BASE_SECONDS, 0, ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_SECONDS) if with_backoff
140
+
141
+ loop do
142
+ remaining_attempts -= 1
143
+
144
+ @segment_fetcher.fetch_segment(name, fetch_options)
145
+
146
+ return sync_result(true, remaining_attempts) if target_cn <= @segments_repository.get_change_number(name).to_i
147
+ return sync_result(false, remaining_attempts) if remaining_attempts <= 0
148
+
149
+ delay = with_backoff ? backoff.interval : retry_delay_seconds
150
+ sleep(delay)
151
+ end
152
+ end
153
+
154
+ def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_seconds, with_backoff)
155
+ remaining_attempts = max_retries
156
+ backoff = Engine::BackOff.new(ON_DEMAND_FETCH_BACKOFF_BASE_SECONDS, 0, ON_DEMAND_FETCH_BACKOFF_MAX_WAIT_SECONDS) if with_backoff
157
+
158
+ loop do
159
+ remaining_attempts -= 1
160
+
161
+ result = @split_fetcher.fetch_splits(fetch_options)
162
+
163
+ return sync_result(true, remaining_attempts, result[:segment_names]) if target_cn <= @splits_repository.get_change_number
164
+ return sync_result(false, remaining_attempts, result[:segment_names]) if remaining_attempts <= 0
165
+
166
+ delay = with_backoff ? backoff.interval : retry_delay_seconds
167
+ sleep(delay)
168
+ end
70
169
  end
71
170
 
72
171
  # Starts thread which loops constantly and sends impressions to the Split API
@@ -87,6 +186,17 @@ module SplitIoClient
87
186
  def start_telemetry_sync_task
88
187
  Telemetry::SyncTask.new(@config, @telemetry_synchronizer).call
89
188
  end
189
+
190
+ def sync_result(success, remaining_attempts, segment_names = nil)
191
+ { success: success, remaining_attempts: remaining_attempts, segment_names: segment_names }
192
+ end
193
+
194
+ def sync_splits_and_segments
195
+ @config.logger.debug('Synchronizing Splits and Segments ...') if @config.debug_enabled
196
+ splits_result = @split_fetcher.fetch_splits
197
+
198
+ splits_result[:success] && @segment_fetcher.fetch_segments
199
+ end
90
200
  end
91
201
  end
92
202
  end
@@ -4,9 +4,9 @@ module SplitIoClient
4
4
  # Creates a new split manager instance that connects to split.io API.
5
5
  #
6
6
  # @return [SplitIoManager] split.io client instance
7
- def initialize(splits_repository = nil, sdk_blocker, config)
7
+ def initialize(splits_repository = nil, status_manager, config)
8
8
  @splits_repository = splits_repository
9
- @sdk_blocker = sdk_blocker
9
+ @status_manager = status_manager
10
10
  @config = config
11
11
  end
12
12
 
@@ -78,7 +78,7 @@ module SplitIoClient
78
78
  end
79
79
 
80
80
  def block_until_ready(time = nil)
81
- @sdk_blocker.block(time) if @sdk_blocker && !@sdk_blocker.ready?
81
+ @status_manager.wait_until_ready(time) if @status_manager
82
82
  end
83
83
 
84
84
  private
@@ -111,7 +111,7 @@ module SplitIoClient
111
111
 
112
112
  # move to blocker, alongside block until ready to avoid duplication
113
113
  def ready?
114
- return @sdk_blocker.ready? if @sdk_blocker
114
+ return @status_manager.ready? if @status_manager
115
115
  true
116
116
  end
117
117
  end
@@ -113,6 +113,9 @@ module SplitIoClient
113
113
 
114
114
  @sdk_start_time = Time.now
115
115
 
116
+ @on_demand_fetch_retry_delay_seconds = SplitConfig.default_on_demand_fetch_retry_delay_seconds
117
+ @on_demand_fetch_max_retries = SplitConfig.default_on_demand_fetch_max_retries
118
+
116
119
  startup_log
117
120
  end
118
121
 
@@ -278,6 +281,17 @@ module SplitIoClient
278
281
 
279
282
  attr_accessor :sdk_start_time
280
283
 
284
+ attr_accessor :on_demand_fetch_retry_delay_seconds
285
+ attr_accessor :on_demand_fetch_max_retries
286
+
287
+ def self.default_on_demand_fetch_retry_delay_seconds
288
+ 0.05
289
+ end
290
+
291
+ def self.default_on_demand_fetch_max_retries
292
+ 10
293
+ end
294
+
281
295
  def self.default_impressions_mode
282
296
  :optimized
283
297
  end
@@ -34,16 +34,16 @@ module SplitIoClient
34
34
  @segments_repository = SegmentsRepository.new(@config)
35
35
  @impressions_repository = ImpressionsRepository.new(@config)
36
36
  @events_repository = EventsRepository.new(@config, @api_key, @runtime_producer)
37
- @sdk_blocker = SDKBlocker.new(@splits_repository, @segments_repository, @config)
38
37
  @impression_counter = SplitIoClient::Engine::Common::ImpressionCounter.new
39
38
  @impressions_manager = SplitIoClient::Engine::Common::ImpressionManager.new(@config, @impressions_repository, @impression_counter, @runtime_producer)
40
39
  @telemetry_api = SplitIoClient::Api::TelemetryApi.new(@config, @api_key, @runtime_producer)
41
40
  @telemetry_synchronizer = Telemetry::Synchronizer.new(@config, @telemetry_consumers, @init_producer, repositories, @telemetry_api)
41
+ @status_manager = Engine::StatusManager.new(@config)
42
42
 
43
43
  start!
44
44
 
45
- @client = SplitClient.new(@api_key, repositories, @sdk_blocker, @config, @impressions_manager, @evaluation_producer)
46
- @manager = SplitManager.new(@splits_repository, @sdk_blocker, @config)
45
+ @client = SplitClient.new(@api_key, repositories, @status_manager, @config, @impressions_manager, @evaluation_producer)
46
+ @manager = SplitManager.new(@splits_repository, @status_manager, @config)
47
47
 
48
48
  validate_api_key
49
49
 
@@ -51,22 +51,20 @@ module SplitIoClient
51
51
  end
52
52
 
53
53
  def start!
54
- if @config.localhost_mode
55
- start_localhost_components
56
- else
57
- split_fetcher = SplitFetcher.new(@splits_repository, @api_key, config, @sdk_blocker, @runtime_producer)
58
- segment_fetcher = SegmentFetcher.new(@segments_repository, @api_key, config, @sdk_blocker, @runtime_producer)
59
- params = {
60
- split_fetcher: split_fetcher,
61
- segment_fetcher: segment_fetcher,
62
- imp_counter: @impression_counter,
63
- telemetry_runtime_producer: @runtime_producer,
64
- telemetry_synchronizer: @telemetry_synchronizer
65
- }
66
-
67
- synchronizer = SplitIoClient::Engine::Synchronizer.new(repositories, @api_key, @config, @sdk_blocker, params)
68
- SplitIoClient::Engine::SyncManager.new(repositories, @api_key, @config, synchronizer, @runtime_producer, @sdk_blocker, @telemetry_synchronizer).start
69
- end
54
+ return start_localhost_components if @config.localhost_mode
55
+
56
+ split_fetcher = SplitFetcher.new(@splits_repository, @api_key, config, @runtime_producer)
57
+ segment_fetcher = SegmentFetcher.new(@segments_repository, @api_key, config, @runtime_producer)
58
+ params = {
59
+ split_fetcher: split_fetcher,
60
+ segment_fetcher: segment_fetcher,
61
+ imp_counter: @impression_counter,
62
+ telemetry_runtime_producer: @runtime_producer,
63
+ telemetry_synchronizer: @telemetry_synchronizer
64
+ }
65
+
66
+ synchronizer = SplitIoClient::Engine::Synchronizer.new(repositories, @api_key, @config, params)
67
+ SplitIoClient::Engine::SyncManager.new(repositories, @api_key, @config, synchronizer, @runtime_producer, @telemetry_synchronizer, @status_manager).start
70
68
  end
71
69
 
72
70
  def stop!
@@ -145,7 +143,7 @@ module SplitIoClient
145
143
  end
146
144
 
147
145
  def start_localhost_components
148
- LocalhostSplitStore.new(@splits_repository, @config, @sdk_blocker).call
146
+ LocalhostSplitStore.new(@splits_repository, @config, @status_manager).call
149
147
 
150
148
  # Starts thread which loops constantly and cleans up repositories to avoid memory issues in localhost mode
151
149
  LocalhostRepoCleaner.new(@impressions_repository, @events_repository, @config).call
@@ -38,7 +38,6 @@ module SplitIoClient
38
38
  def close(action = Constants::PUSH_NONRETRYABLE_ERROR)
39
39
  dispatch_action(action)
40
40
  @connected.make_false
41
- SplitIoClient::Helpers::ThreadHelper.stop(:connect_stream, @config)
42
41
  @socket&.close
43
42
  rescue StandardError => e
44
43
  @config.logger.error("SSEClient close Error: #{e.inspect}")
@@ -77,7 +76,7 @@ module SplitIoClient
77
76
  end
78
77
 
79
78
  def connect_stream(latch)
80
- socket_write
79
+ socket_write(latch)
81
80
 
82
81
  while connected? || @first_event.value
83
82
  begin
@@ -96,13 +95,14 @@ module SplitIoClient
96
95
  end
97
96
  end
98
97
 
99
- def socket_write
98
+ def socket_write(latch)
100
99
  @first_event.make_true
101
100
  @socket = socket_connect
102
101
  @socket.write(build_request(@uri))
103
102
  rescue StandardError => e
104
103
  @config.logger.error("Error during connecting to #{@uri.host}. Error: #{e.inspect}")
105
104
  close(Constants::PUSH_NONRETRYABLE_ERROR)
105
+ latch.count_down
106
106
  end
107
107
 
108
108
  def read_first_event(data, latch)
@@ -51,11 +51,7 @@ module SplitIoClient
51
51
  cn = item[:change_number]
52
52
  @config.logger.debug("SegmentsWorker change_number dequeue #{segment_name}, #{cn}")
53
53
 
54
- attempt = 0
55
- while cn > @segments_repository.get_change_number(segment_name).to_i && attempt <= Workers::MAX_RETRIES_ALLOWED
56
- @synchronizer.fetch_segment(segment_name)
57
- attempt += 1
58
- end
54
+ @synchronizer.fetch_segment(segment_name, cn)
59
55
  end
60
56
  end
61
57
 
@@ -3,8 +3,6 @@
3
3
  module SplitIoClient
4
4
  module SSE
5
5
  module Workers
6
- MAX_RETRIES_ALLOWED = 10
7
-
8
6
  class SplitsWorker
9
7
  def initialize(synchronizer, config, splits_repository)
10
8
  @synchronizer = synchronizer
@@ -62,12 +60,7 @@ module SplitIoClient
62
60
  def perform
63
61
  while (change_number = @queue.pop)
64
62
  @config.logger.debug("SplitsWorker change_number dequeue #{change_number}")
65
-
66
- attempt = 0
67
- while change_number > @splits_repository.get_change_number.to_i && attempt <= Workers::MAX_RETRIES_ALLOWED
68
- @synchronizer.fetch_splits
69
- attempt += 1
70
- end
63
+ @synchronizer.fetch_splits(change_number)
71
64
  end
72
65
  end
73
66
 
@@ -1,3 +1,3 @@
1
1
  module SplitIoClient
2
- VERSION = '7.3.0.pre.rc3'
2
+ VERSION = '7.3.2.pre.rc1'
3
3
  end
@@ -28,10 +28,9 @@ require 'splitclient-rb/cache/senders/impressions_sender'
28
28
  require 'splitclient-rb/cache/senders/events_sender'
29
29
  require 'splitclient-rb/cache/senders/impressions_count_sender'
30
30
  require 'splitclient-rb/cache/senders/localhost_repo_cleaner'
31
- require 'splitclient-rb/cache/stores/store_utils'
32
31
  require 'splitclient-rb/cache/stores/localhost_split_builder'
33
- require 'splitclient-rb/cache/stores/sdk_blocker'
34
32
  require 'splitclient-rb/cache/stores/localhost_split_store'
33
+ require 'splitclient-rb/cache/stores/store_utils'
35
34
 
36
35
  require 'splitclient-rb/clients/split_client'
37
36
  require 'splitclient-rb/managers/split_manager'
@@ -85,13 +84,14 @@ require 'splitclient-rb/engine/models/split'
85
84
  require 'splitclient-rb/engine/models/label'
86
85
  require 'splitclient-rb/engine/models/treatment'
87
86
  require 'splitclient-rb/engine/auth_api_client'
87
+ require 'splitclient-rb/engine/back_off'
88
88
  require 'splitclient-rb/engine/push_manager'
89
+ require 'splitclient-rb/engine/status_manager'
89
90
  require 'splitclient-rb/engine/sync_manager'
90
91
  require 'splitclient-rb/engine/synchronizer'
91
92
  require 'splitclient-rb/utilitites'
92
93
 
93
- # SSE
94
- require 'splitclient-rb/sse/event_source/back_off'
94
+ # SSE
95
95
  require 'splitclient-rb/sse/event_source/client'
96
96
  require 'splitclient-rb/sse/event_source/event_parser'
97
97
  require 'splitclient-rb/sse/event_source/event_types'
@@ -38,14 +38,15 @@ Gem::Specification.new do |spec|
38
38
 
39
39
  spec.add_development_dependency 'allocation_stats'
40
40
  spec.add_development_dependency 'appraisal'
41
- spec.add_development_dependency 'bundler', '~> 1.11'
41
+ spec.add_development_dependency 'bundler', '~> 2.2'
42
42
  spec.add_development_dependency 'pry'
43
43
  spec.add_development_dependency 'pry-nav'
44
44
  spec.add_development_dependency 'rake', '12.3.3'
45
45
  spec.add_development_dependency 'rake-compiler'
46
46
  spec.add_development_dependency 'rspec'
47
47
  spec.add_development_dependency 'rubocop', '0.59.0'
48
- spec.add_development_dependency 'simplecov'
48
+ spec.add_development_dependency 'simplecov', '0.20.0'
49
+ spec.add_development_dependency 'simplecov-json'
49
50
  spec.add_development_dependency 'timecop'
50
51
  spec.add_development_dependency 'webmock'
51
52
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: splitclient-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.3.0.pre.rc3
4
+ version: 7.3.2.pre.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Split Software
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-25 00:00:00.000000000 Z
11
+ date: 2021-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: allocation_stats
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.11'
47
+ version: '2.2'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.11'
54
+ version: '2.2'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: pry
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -138,6 +138,20 @@ dependencies:
138
138
  version: 0.59.0
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: simplecov
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '='
144
+ - !ruby/object:Gem::Version
145
+ version: 0.20.0
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '='
151
+ - !ruby/object:Gem::Version
152
+ version: 0.20.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: simplecov-json
141
155
  requirement: !ruby/object:Gem::Requirement
142
156
  requirements:
143
157
  - - ">="
@@ -313,10 +327,10 @@ extensions:
313
327
  extra_rdoc_files: []
314
328
  files:
315
329
  - ".github/pull_request_template.md"
330
+ - ".github/workflows/ci.yml"
316
331
  - ".gitignore"
317
332
  - ".rubocop.yml"
318
333
  - ".simplecov"
319
- - ".travis.yml"
320
334
  - Appraisals
321
335
  - CHANGES.txt
322
336
  - CONTRIBUTORS-GUIDE.md
@@ -361,7 +375,6 @@ files:
361
375
  - lib/splitclient-rb/cache/senders/localhost_repo_cleaner.rb
362
376
  - lib/splitclient-rb/cache/stores/localhost_split_builder.rb
363
377
  - lib/splitclient-rb/cache/stores/localhost_split_store.rb
364
- - lib/splitclient-rb/cache/stores/sdk_blocker.rb
365
378
  - lib/splitclient-rb/cache/stores/store_utils.rb
366
379
  - lib/splitclient-rb/clients/split_client.rb
367
380
  - lib/splitclient-rb/constants.rb
@@ -374,6 +387,7 @@ files:
374
387
  - lib/splitclient-rb/engine/api/splits.rb
375
388
  - lib/splitclient-rb/engine/api/telemetry_api.rb
376
389
  - lib/splitclient-rb/engine/auth_api_client.rb
390
+ - lib/splitclient-rb/engine/back_off.rb
377
391
  - lib/splitclient-rb/engine/common/impressions_counter.rb
378
392
  - lib/splitclient-rb/engine/common/impressions_manager.rb
379
393
  - lib/splitclient-rb/engine/evaluator/splitter.rb
@@ -407,6 +421,7 @@ files:
407
421
  - lib/splitclient-rb/engine/parser/evaluator.rb
408
422
  - lib/splitclient-rb/engine/parser/partition.rb
409
423
  - lib/splitclient-rb/engine/push_manager.rb
424
+ - lib/splitclient-rb/engine/status_manager.rb
410
425
  - lib/splitclient-rb/engine/sync_manager.rb
411
426
  - lib/splitclient-rb/engine/synchronizer.rb
412
427
  - lib/splitclient-rb/exceptions.rb
@@ -417,7 +432,6 @@ files:
417
432
  - lib/splitclient-rb/split_factory_builder.rb
418
433
  - lib/splitclient-rb/split_factory_registry.rb
419
434
  - lib/splitclient-rb/split_logger.rb
420
- - lib/splitclient-rb/sse/event_source/back_off.rb
421
435
  - lib/splitclient-rb/sse/event_source/client.rb
422
436
  - lib/splitclient-rb/sse/event_source/event_parser.rb
423
437
  - lib/splitclient-rb/sse/event_source/event_types.rb
@@ -451,7 +465,6 @@ files:
451
465
  - lib/splitclient-rb/utilitites.rb
452
466
  - lib/splitclient-rb/validators.rb
453
467
  - lib/splitclient-rb/version.rb
454
- - sonar-scanner.sh
455
468
  - splitclient-rb.gemspec
456
469
  - tasks/benchmark_get_treatment.rake
457
470
  - tasks/irb.rake
@@ -459,7 +472,7 @@ homepage: https://github.com/splitio/ruby-client
459
472
  licenses:
460
473
  - Apache-2.0
461
474
  metadata: {}
462
- post_install_message:
475
+ post_install_message:
463
476
  rdoc_options: []
464
477
  require_paths:
465
478
  - lib
@@ -474,8 +487,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
474
487
  - !ruby/object:Gem::Version
475
488
  version: 1.3.1
476
489
  requirements: []
477
- rubygems_version: 3.0.6
478
- signing_key:
490
+ rubygems_version: 3.2.32
491
+ signing_key:
479
492
  specification_version: 4
480
493
  summary: Ruby client for split SDK.
481
494
  test_files: []
data/.travis.yml DELETED
@@ -1,20 +0,0 @@
1
- language: ruby
2
-
3
- rvm:
4
- - "2.3.6"
5
-
6
- services:
7
- - redis-server
8
-
9
- addons:
10
- sonarqube: true
11
-
12
- git:
13
- depth: false
14
-
15
- before_install:
16
- - gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
17
- - gem install bundler -v '< 2'
18
-
19
- after_success:
20
- - bash sonar-scanner.sh
@@ -1,64 +0,0 @@
1
- require 'thread'
2
- require 'timeout'
3
-
4
- module SplitIoClient
5
- module Cache
6
- module Stores
7
- class SDKBlocker
8
- attr_reader :splits_repository
9
-
10
- def initialize(splits_repository, segments_repository, config)
11
- @splits_repository = splits_repository
12
- @segments_repository = segments_repository
13
- @config = config
14
- @internal_ready = Concurrent::CountDownLatch.new(1)
15
-
16
- if @config.standalone?
17
- @splits_repository.not_ready!
18
- @segments_repository.not_ready!
19
- end
20
- end
21
-
22
- def splits_ready!
23
- if !ready?
24
- @splits_repository.ready!
25
- @config.logger.info('splits are ready')
26
- end
27
- end
28
-
29
- def segments_ready!
30
- if !ready?
31
- @segments_repository.ready!
32
- @config.logger.info('segments are ready')
33
- end
34
- end
35
-
36
- def block(time = nil)
37
- begin
38
- timeout = time || @config.block_until_ready
39
- Timeout::timeout(timeout) do
40
- sleep 0.1 until ready?
41
- end
42
- rescue Timeout::Error
43
- fail SDKBlockerTimeoutExpiredException, 'SDK start up timeout expired'
44
- end
45
-
46
- @config.logger.info('SplitIO SDK is ready')
47
- end
48
-
49
- def ready?
50
- return true if @config.consumer?
51
- @splits_repository.ready? && @segments_repository.ready?
52
- end
53
-
54
- def sdk_internal_ready
55
- @internal_ready.count_down
56
- end
57
-
58
- def wait_unitil_internal_ready
59
- @internal_ready.wait
60
- end
61
- end
62
- end
63
- end
64
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: false
2
-
3
- module SplitIoClient
4
- module SSE
5
- module EventSource
6
- class BackOff
7
- def initialize(back_off_base, attempt = 0)
8
- @attempt = attempt
9
- @back_off_base = back_off_base
10
- end
11
-
12
- def interval
13
- interval = (@back_off_base * (2**@attempt)) if @attempt.positive?
14
- @attempt += 1
15
-
16
- interval || 0
17
- end
18
-
19
- def reset
20
- @attempt = 0
21
- end
22
- end
23
- end
24
- end
25
- end
data/sonar-scanner.sh DELETED
@@ -1,42 +0,0 @@
1
- #/bin/bash -e
2
-
3
- sonar_scanner() {
4
- local params=$@
5
-
6
- sonar-scanner \
7
- -Dsonar.host.url='https://sonarqube.split-internal.com' \
8
- -Dsonar.login="$SONAR_TOKEN" \
9
- -Dsonar.ws.timeout='300' \
10
- -Dsonar.sources='lib' \
11
- -Dsonar.projectName='ruby-client' \
12
- -Dsonar.projectKey='ruby-client' \
13
- -Dsonar.ruby.coverage.reportPaths='coverage/.resultset.json' \
14
- -Dsonar.links.ci='https://travis-ci.com/splitio/ruby-client' \
15
- -Dsonar.links.scm='https://github.com/splitio/ruby-client' \
16
- ${params}
17
-
18
- return $?
19
- }
20
-
21
- if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
22
- sonar_scanner \
23
- -Dsonar.pullrequest.provider='GitHub' \
24
- -Dsonar.pullrequest.github.repository='splitio/ruby-client' \
25
- -Dsonar.pullrequest.key=$TRAVIS_PULL_REQUEST \
26
- -Dsonar.pullrequest.branch=$TRAVIS_PULL_REQUEST_BRANCH \
27
- -Dsonar.pullrequest.base=$TRAVIS_BRANCH
28
- else
29
- if [ "$TRAVIS_BRANCH" == 'master' ]; then
30
- sonar_scanner \
31
- -Dsonar.branch.name=$TRAVIS_BRANCH
32
- else
33
- if [ "$TRAVIS_BRANCH" == 'development' ]; then
34
- TARGET_BRANCH='master'
35
- else
36
- TARGET_BRANCH='development'
37
- fi
38
- sonar_scanner \
39
- -Dsonar.branch.name=$TRAVIS_BRANCH \
40
- -Dsonar.branch.target=$TARGET_BRANCH
41
- fi
42
- fi