splitclient-rb 7.0.4.pre.rc3 → 7.1.0.pre.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -3
- data/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb +4 -0
- data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +4 -1
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +1 -1
- data/lib/splitclient-rb/clients/split_client.rb +4 -7
- data/lib/splitclient-rb/constants.rb +9 -0
- data/lib/splitclient-rb/engine/api/splits.rb +0 -1
- data/lib/splitclient-rb/engine/auth_api_client.rb +78 -0
- data/lib/splitclient-rb/engine/push_manager.rb +46 -0
- data/lib/splitclient-rb/engine/sync_manager.rb +112 -0
- data/lib/splitclient-rb/engine/synchronizer.rb +80 -0
- data/lib/splitclient-rb/exceptions.rb +8 -0
- data/lib/splitclient-rb/helpers/thread_helper.rb +19 -0
- data/lib/splitclient-rb/split_config.rb +42 -4
- data/lib/splitclient-rb/split_factory.rb +25 -15
- data/lib/splitclient-rb/sse/event_source/back_off.rb +25 -0
- data/lib/splitclient-rb/sse/event_source/client.rb +73 -50
- data/lib/splitclient-rb/sse/event_source/stream_data.rb +22 -0
- data/lib/splitclient-rb/sse/notification_manager_keeper.rb +45 -0
- data/lib/splitclient-rb/sse/notification_processor.rb +50 -0
- data/lib/splitclient-rb/sse/sse_handler.rb +46 -50
- data/lib/splitclient-rb/sse/workers/control_worker.rb +10 -5
- data/lib/splitclient-rb/sse/workers/segments_worker.rb +14 -4
- data/lib/splitclient-rb/sse/workers/splits_worker.rb +16 -4
- data/lib/splitclient-rb/version.rb +1 -1
- data/lib/splitclient-rb.rb +10 -2
- data/splitclient-rb.gemspec +1 -0
- metadata +26 -4
- data/lib/splitclient-rb/engine/parser/split_adapter.rb +0 -105
- data/lib/splitclient-rb/sse/event_source/status.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: faa0e8b87fc65523dcfa6611ddb9e672fbd213487aea472455435aa080c29f60
|
4
|
+
data.tar.gz: 69b8a67b002dadd9b92e20d04bf18f4a05756ded1822039c48e47ff12a4e20e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b95e354b732d3377dc4d4bd5daf1b20d05b31e68478cb9e045f9f89b60a04c6834995a1522e7db43e450beeeec0bfb96547408f4f82032c80ad9117b7ac911be
|
7
|
+
data.tar.gz: 573ac96c29360b36f0091992604e3acd970732ca609377f1895776b1750dfc59d5627025c10ad8472c066a5b551fae0df87ff0db17ed3afe817bdfb12f1d42b7
|
data/.rubocop.yml
CHANGED
@@ -2,16 +2,16 @@ Documentation:
|
|
2
2
|
Enabled: false
|
3
3
|
|
4
4
|
Metrics/AbcSize:
|
5
|
-
Max:
|
5
|
+
Max: 26
|
6
6
|
|
7
7
|
Metrics/MethodLength:
|
8
8
|
Max: 20
|
9
9
|
|
10
10
|
Metrics/ClassLength:
|
11
|
-
Max:
|
11
|
+
Max: 140
|
12
12
|
|
13
13
|
Metrics/LineLength:
|
14
|
-
Max:
|
14
|
+
Max: 130
|
15
15
|
Exclude:
|
16
16
|
- spec/sse/**/*
|
17
17
|
|
@@ -39,11 +39,14 @@ module SplitIoClient
|
|
39
39
|
@config.logger.debug("segments seen(#{data[:segment_names].length}): #{data[:segment_names].to_a}") if @config.debug_enabled
|
40
40
|
|
41
41
|
@sdk_blocker.splits_ready!
|
42
|
-
|
43
42
|
rescue StandardError => error
|
44
43
|
@config.log_found_exception(__method__.to_s, error)
|
45
44
|
end
|
46
45
|
|
46
|
+
def stop_splits_thread
|
47
|
+
SplitIoClient::Helpers::ThreadHelper.stop(:split_fetcher, @config)
|
48
|
+
end
|
49
|
+
|
47
50
|
private
|
48
51
|
|
49
52
|
def splits_thread
|
@@ -9,8 +9,9 @@ module SplitIoClient
|
|
9
9
|
# @param api_key [String] the API key for your split account
|
10
10
|
#
|
11
11
|
# @return [SplitIoClient] split.io client instance
|
12
|
-
def initialize(api_key,
|
12
|
+
def initialize(api_key, metrics, splits_repository, segments_repository, impressions_repository, metrics_repository, events_repository, sdk_blocker, config)
|
13
13
|
@api_key = api_key
|
14
|
+
@metrics = metrics
|
14
15
|
@splits_repository = splits_repository
|
15
16
|
@segments_repository = segments_repository
|
16
17
|
@impressions_repository = impressions_repository
|
@@ -19,8 +20,6 @@ module SplitIoClient
|
|
19
20
|
@sdk_blocker = sdk_blocker
|
20
21
|
@destroyed = false
|
21
22
|
@config = config
|
22
|
-
@adapter = adapter
|
23
|
-
@sse_handler = sse_handler
|
24
23
|
end
|
25
24
|
|
26
25
|
def get_treatment(
|
@@ -62,8 +61,6 @@ module SplitIoClient
|
|
62
61
|
thread.join
|
63
62
|
end
|
64
63
|
|
65
|
-
@sse_handler.sse_client.close if @config.push_notification_enabled
|
66
|
-
|
67
64
|
@config.threads.values.each { |thread| Thread.kill(thread) }
|
68
65
|
|
69
66
|
@splits_repository.clear
|
@@ -252,7 +249,7 @@ module SplitIoClient
|
|
252
249
|
end
|
253
250
|
latency = (Time.now - start) * 1000.0
|
254
251
|
# Measure
|
255
|
-
@
|
252
|
+
@metrics.time('sdk.' + calling_method, latency)
|
256
253
|
|
257
254
|
treatments_for_impressions = get_treatment_for_impressions(treatments_labels_change_numbers)
|
258
255
|
|
@@ -336,7 +333,7 @@ module SplitIoClient
|
|
336
333
|
store_impression(split_name, matching_key, bucketing_key, treatment_data, attributes) if store_impressions
|
337
334
|
|
338
335
|
# Measure
|
339
|
-
@
|
336
|
+
@metrics.time('sdk.' + calling_method, latency) unless multiple
|
340
337
|
rescue StandardError => error
|
341
338
|
@config.log_found_exception(__method__.to_s, error)
|
342
339
|
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'jwt'
|
4
|
+
require 'cgi'
|
5
|
+
|
6
|
+
module SplitIoClient
|
7
|
+
module Engine
|
8
|
+
class AuthApiClient
|
9
|
+
def initialize(config)
|
10
|
+
@config = config
|
11
|
+
@api_client = SplitIoClient::Api::Client.new(@config)
|
12
|
+
end
|
13
|
+
|
14
|
+
def authenticate(api_key)
|
15
|
+
response = @api_client.get_api(@config.auth_service_url, api_key)
|
16
|
+
|
17
|
+
return process_success(response) if response.success?
|
18
|
+
|
19
|
+
if response.status >= 400 && response.status < 500
|
20
|
+
@config.logger.debug("Problem to connect to: #{@config.auth_service_url}. Response status: #{response.status}")
|
21
|
+
|
22
|
+
return { push_enabled: false, retry: false }
|
23
|
+
end
|
24
|
+
|
25
|
+
@config.logger.debug("Problem to connect to: #{@config.auth_service_url}. Response status: #{response.status}")
|
26
|
+
{ push_enabled: false, retry: true }
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def expiration(token_decoded)
|
32
|
+
exp = token_decoded[0]['exp']
|
33
|
+
|
34
|
+
(exp - SplitIoClient::Constants::EXPIRATION_RATE) - Time.now.getutc.to_i unless exp.nil?
|
35
|
+
rescue StandardError => e
|
36
|
+
@config.logger.error("Error getting token expiration: #{e.inspect}")
|
37
|
+
end
|
38
|
+
|
39
|
+
def channels(token_decoded)
|
40
|
+
capability = token_decoded[0]['x-ably-capability']
|
41
|
+
channels_hash = JSON.parse(capability)
|
42
|
+
channels_string = channels_hash.keys.join(',')
|
43
|
+
channels_string = control_channels(channels_string)
|
44
|
+
@config.logger.debug("Channels #{channels_string}")
|
45
|
+
CGI.escape(channels_string)
|
46
|
+
end
|
47
|
+
|
48
|
+
def decode_token(token)
|
49
|
+
JWT.decode token, nil, false
|
50
|
+
end
|
51
|
+
|
52
|
+
def process_success(response)
|
53
|
+
@config.logger.debug("Success connection to: #{@config.auth_service_url}")
|
54
|
+
|
55
|
+
body_json = JSON.parse(response.body, symbolize_names: true)
|
56
|
+
push_enabled = body_json[:pushEnabled]
|
57
|
+
token = body_json[:token]
|
58
|
+
|
59
|
+
if push_enabled
|
60
|
+
decoded_token = decode_token(token)
|
61
|
+
channels = channels(decoded_token)
|
62
|
+
exp = expiration(decoded_token)
|
63
|
+
end
|
64
|
+
|
65
|
+
{ push_enabled: push_enabled, token: token, channels: channels, exp: exp, retry: false }
|
66
|
+
end
|
67
|
+
|
68
|
+
def control_channels(channels_string)
|
69
|
+
prefix = SplitIoClient::Constants::OCCUPANCY_CHANNEL_PREFIX
|
70
|
+
control_pri = SplitIoClient::Constants::CONTROL_PRI
|
71
|
+
control_sec = SplitIoClient::Constants::CONTROL_SEC
|
72
|
+
channels_string = channels_string.gsub(control_pri, "#{prefix}#{control_pri}")
|
73
|
+
channels_string = channels_string.gsub(control_sec, "#{prefix}#{control_sec}")
|
74
|
+
channels_string
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SplitIoClient
|
4
|
+
module Engine
|
5
|
+
class PushManager
|
6
|
+
def initialize(config, sse_handler, api_key)
|
7
|
+
@config = config
|
8
|
+
@sse_handler = sse_handler
|
9
|
+
@auth_api_client = AuthApiClient.new(@config)
|
10
|
+
@api_key = api_key
|
11
|
+
@back_off = SplitIoClient::SSE::EventSource::BackOff.new(@config.auth_retry_back_off_base)
|
12
|
+
end
|
13
|
+
|
14
|
+
def start_sse
|
15
|
+
response = @auth_api_client.authenticate(@api_key)
|
16
|
+
|
17
|
+
if response[:push_enabled]
|
18
|
+
@sse_handler.start(response[:token], response[:channels])
|
19
|
+
schedule_next_token_refresh(response[:exp])
|
20
|
+
@back_off.reset
|
21
|
+
else
|
22
|
+
stop_sse
|
23
|
+
end
|
24
|
+
|
25
|
+
schedule_next_token_refresh(@back_off.interval) if response[:retry]
|
26
|
+
rescue StandardError => e
|
27
|
+
@config.logger.error("start_sse: #{e.inspect}")
|
28
|
+
end
|
29
|
+
|
30
|
+
def stop_sse
|
31
|
+
@sse_handler.process_disconnect if @sse_handler.sse_client.nil?
|
32
|
+
@sse_handler.stop
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def schedule_next_token_refresh(time)
|
38
|
+
@config.threads[:schedule_next_token_refresh] = Thread.new do
|
39
|
+
sleep(time)
|
40
|
+
stop_sse
|
41
|
+
start_sse
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SplitIoClient
|
4
|
+
module Engine
|
5
|
+
class SyncManager
|
6
|
+
include SplitIoClient::Cache::Fetchers
|
7
|
+
|
8
|
+
def initialize(
|
9
|
+
repositories,
|
10
|
+
api_key,
|
11
|
+
config,
|
12
|
+
sdk_blocker,
|
13
|
+
metrics
|
14
|
+
)
|
15
|
+
split_fetcher = SplitFetcher.new(repositories[:splits], api_key, metrics, config, sdk_blocker)
|
16
|
+
segment_fetcher = SegmentFetcher.new(repositories[:segments], api_key, metrics, config, sdk_blocker)
|
17
|
+
sync_params = { split_fetcher: split_fetcher, segment_fetcher: segment_fetcher }
|
18
|
+
|
19
|
+
@synchronizer = Synchronizer.new(repositories, api_key, config, sdk_blocker, sync_params)
|
20
|
+
notification_manager_keeper = SplitIoClient::SSE::NotificationManagerKeeper.new(config) do |manager|
|
21
|
+
manager.on_occupancy { |publisher_available| process_occupancy(publisher_available) }
|
22
|
+
end
|
23
|
+
@sse_handler = SplitIoClient::SSE::SSEHandler.new(
|
24
|
+
config,
|
25
|
+
@synchronizer,
|
26
|
+
repositories[:splits],
|
27
|
+
repositories[:segments],
|
28
|
+
notification_manager_keeper
|
29
|
+
) do |handler|
|
30
|
+
handler.on_connected { process_connected }
|
31
|
+
handler.on_disconnect { process_disconnect }
|
32
|
+
end
|
33
|
+
|
34
|
+
@push_manager = PushManager.new(config, @sse_handler, api_key)
|
35
|
+
@config = config
|
36
|
+
end
|
37
|
+
|
38
|
+
def start
|
39
|
+
if @config.streaming_enabled
|
40
|
+
start_stream
|
41
|
+
elsif @config.standalone?
|
42
|
+
start_poll
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# Starts tasks if stream is enabled.
|
49
|
+
def start_stream
|
50
|
+
stream_start_thread
|
51
|
+
stream_start_thread_forked if defined?(PhusionPassenger)
|
52
|
+
|
53
|
+
stream_start_sse_thread
|
54
|
+
stream_start_sse_thread_forked if defined?(PhusionPassenger)
|
55
|
+
end
|
56
|
+
|
57
|
+
def start_poll
|
58
|
+
@synchronizer.start_periodic_fetch
|
59
|
+
@synchronizer.start_periodic_data_recording
|
60
|
+
rescue StandardError => error
|
61
|
+
@config.logger.error(error)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Starts thread which fetch splits and segments once and trigger task to periodic data recording.
|
65
|
+
def stream_start_thread
|
66
|
+
@config.threads[:sync_manager_start_stream] = Thread.new do
|
67
|
+
begin
|
68
|
+
@synchronizer.sync_all
|
69
|
+
@synchronizer.start_periodic_data_recording
|
70
|
+
rescue StandardError => error
|
71
|
+
@config.logger.error(error)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Starts thread which connect to sse and after that fetch splits and segments once.
|
77
|
+
def stream_start_sse_thread
|
78
|
+
@config.threads[:sync_manager_start_sse] = Thread.new do
|
79
|
+
begin
|
80
|
+
@push_manager.start_sse
|
81
|
+
rescue StandardError => error
|
82
|
+
@config.logger.error(error)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def stream_start_thread_forked
|
88
|
+
PhusionPassenger.on_event(:starting_worker_process) { |forked| stream_start_thread if forked }
|
89
|
+
end
|
90
|
+
|
91
|
+
def stream_start_sse_thread_forked
|
92
|
+
PhusionPassenger.on_event(:starting_worker_process) { |forked| stream_start_sse_thread if forked }
|
93
|
+
end
|
94
|
+
|
95
|
+
def process_connected
|
96
|
+
@synchronizer.stop_periodic_fetch
|
97
|
+
@synchronizer.sync_all
|
98
|
+
@sse_handler.start_workers
|
99
|
+
end
|
100
|
+
|
101
|
+
def process_disconnect
|
102
|
+
@sse_handler.stop_workers
|
103
|
+
@synchronizer.start_periodic_fetch
|
104
|
+
end
|
105
|
+
|
106
|
+
def process_occupancy(publisher_available)
|
107
|
+
process_disconnect unless publisher_available
|
108
|
+
process_connected if publisher_available
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SplitIoClient
|
4
|
+
module Engine
|
5
|
+
class Synchronizer
|
6
|
+
include SplitIoClient::Cache::Fetchers
|
7
|
+
include SplitIoClient::Cache::Senders
|
8
|
+
|
9
|
+
def initialize(
|
10
|
+
repositories,
|
11
|
+
api_key,
|
12
|
+
config,
|
13
|
+
sdk_blocker,
|
14
|
+
params
|
15
|
+
)
|
16
|
+
@splits_repository = repositories[:splits]
|
17
|
+
@segments_repository = repositories[:segments]
|
18
|
+
@impressions_repository = repositories[:impressions]
|
19
|
+
@metrics_repository = repositories[:metrics]
|
20
|
+
@events_repository = repositories[:events]
|
21
|
+
@api_key = api_key
|
22
|
+
@config = config
|
23
|
+
@sdk_blocker = sdk_blocker
|
24
|
+
@split_fetcher = params[:split_fetcher]
|
25
|
+
@segment_fetcher = params[:segment_fetcher]
|
26
|
+
end
|
27
|
+
|
28
|
+
def sync_all
|
29
|
+
@config.logger.debug('Synchronizing Splits and Segments ...')
|
30
|
+
fetch_splits
|
31
|
+
fetch_segments
|
32
|
+
end
|
33
|
+
|
34
|
+
def start_periodic_data_recording
|
35
|
+
@metrics_sender = metrics_sender
|
36
|
+
@impressions_sender = impressions_sender
|
37
|
+
@events_sender = events_sender
|
38
|
+
end
|
39
|
+
|
40
|
+
def start_periodic_fetch
|
41
|
+
@split_fetcher.call
|
42
|
+
@segment_fetcher.call
|
43
|
+
end
|
44
|
+
|
45
|
+
def stop_periodic_fetch
|
46
|
+
@split_fetcher.stop_splits_thread
|
47
|
+
@segment_fetcher.stop_segments_thread
|
48
|
+
end
|
49
|
+
|
50
|
+
def fetch_splits
|
51
|
+
@split_fetcher.fetch_splits
|
52
|
+
end
|
53
|
+
|
54
|
+
def fetch_segment(name)
|
55
|
+
@segment_fetcher.fetch_segment(name)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def fetch_segments
|
61
|
+
@segment_fetcher.fetch_segments
|
62
|
+
end
|
63
|
+
|
64
|
+
# Starts thread which loops constantly and sends impressions to the Split API
|
65
|
+
def impressions_sender
|
66
|
+
ImpressionsSender.new(@impressions_repository, @api_key, @config).call
|
67
|
+
end
|
68
|
+
|
69
|
+
# Starts thread which loops constantly and sends metrics to the Split API
|
70
|
+
def metrics_sender
|
71
|
+
MetricsSender.new(@metrics_repository, @api_key, @config).call
|
72
|
+
end
|
73
|
+
|
74
|
+
# Starts thread which loops constantly and sends events to the Split API
|
75
|
+
def events_sender
|
76
|
+
EventsSender.new(@events_repository, @config).call
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -4,4 +4,12 @@ module SplitIoClient
|
|
4
4
|
class SDKShutdownException < SplitIoError; end
|
5
5
|
|
6
6
|
class SDKBlockerTimeoutExpiredException < SplitIoError; end
|
7
|
+
|
8
|
+
class SSEClientException < SplitIoError
|
9
|
+
attr_reader :event
|
10
|
+
|
11
|
+
def initialize(event)
|
12
|
+
@event = event
|
13
|
+
end
|
14
|
+
end
|
7
15
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SplitIoClient
|
4
|
+
module Helpers
|
5
|
+
class ThreadHelper
|
6
|
+
def self.stop(thread_sym, config)
|
7
|
+
thread = config.threads[thread_sym]
|
8
|
+
|
9
|
+
unless thread.nil?
|
10
|
+
config.logger.debug("Stopping #{thread_sym} ...")
|
11
|
+
sleep(0.1) while thread.status == 'run'
|
12
|
+
Thread.kill(thread)
|
13
|
+
end
|
14
|
+
rescue StandardError => error
|
15
|
+
config.logger.error(error.inspect)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -102,7 +102,11 @@ module SplitIoClient
|
|
102
102
|
@split_validator = SplitIoClient::Validators.new(self)
|
103
103
|
@localhost_mode = opts[:localhost_mode]
|
104
104
|
|
105
|
-
@
|
105
|
+
@streaming_enabled = consumer? ? false : (opts[:streaming_enabled].nil? ? SplitConfig.default_streaming_enabled : opts[:streaming_enabled])
|
106
|
+
@streaming_service_url = opts[:streaming_service_url] || SplitConfig.default_streaming_service_url
|
107
|
+
@auth_service_url = opts[:auth_service_url] || SplitConfig.default_auth_service_url
|
108
|
+
@auth_retry_back_off_base = SplitConfig.init_auth_retry_back_off(opts[:auth_retry_back_off_base] || SplitConfig.default_auth_retry_back_off_base)
|
109
|
+
@streaming_reconnect_back_off_base = SplitConfig.init_streaming_reconnect_back_off(opts[:streaming_reconnect_back_off_base] || SplitConfig.default_streaming_reconnect_back_off_base)
|
106
110
|
|
107
111
|
startup_log
|
108
112
|
end
|
@@ -256,7 +260,43 @@ module SplitIoClient
|
|
256
260
|
|
257
261
|
attr_accessor :ip_addresses_enabled
|
258
262
|
|
259
|
-
attr_accessor :
|
263
|
+
attr_accessor :auth_service_url
|
264
|
+
|
265
|
+
attr_accessor :auth_retry_back_off_base
|
266
|
+
|
267
|
+
attr_accessor :streaming_service_url
|
268
|
+
|
269
|
+
attr_accessor :streaming_reconnect_back_off_base
|
270
|
+
|
271
|
+
attr_accessor :streaming_enabled
|
272
|
+
|
273
|
+
def self.default_streaming_enabled
|
274
|
+
true
|
275
|
+
end
|
276
|
+
|
277
|
+
def self.default_streaming_service_url
|
278
|
+
'https://realtime.ably.io/event-stream'
|
279
|
+
end
|
280
|
+
|
281
|
+
def self.default_auth_service_url
|
282
|
+
'https://auth.split-stage.io/api/auth'
|
283
|
+
end
|
284
|
+
|
285
|
+
def self.default_auth_retry_back_off_base
|
286
|
+
1
|
287
|
+
end
|
288
|
+
|
289
|
+
def self.default_streaming_reconnect_back_off_base
|
290
|
+
1
|
291
|
+
end
|
292
|
+
|
293
|
+
def self.init_auth_retry_back_off(auth_retry_back_off)
|
294
|
+
auth_retry_back_off < 1 ? SplitConfig.default_auth_retry_back_off_base : auth_retry_back_off
|
295
|
+
end
|
296
|
+
|
297
|
+
def self.init_streaming_reconnect_back_off(streaming_reconnect_back_off)
|
298
|
+
streaming_reconnect_back_off < 1 ? SplitConfig.default_streaming_reconnect_back_off_base : streaming_reconnect_back_off
|
299
|
+
end
|
260
300
|
|
261
301
|
#
|
262
302
|
# The default split client configuration
|
@@ -385,8 +425,6 @@ module SplitIoClient
|
|
385
425
|
end
|
386
426
|
end
|
387
427
|
|
388
|
-
|
389
|
-
|
390
428
|
#
|
391
429
|
# The default debug value
|
392
430
|
#
|
@@ -6,6 +6,7 @@ module SplitIoClient
|
|
6
6
|
|
7
7
|
include SplitIoClient::Cache::Repositories
|
8
8
|
include SplitIoClient::Cache::Stores
|
9
|
+
include SplitIoClient::Cache::Senders
|
9
10
|
|
10
11
|
attr_reader :adapter, :client, :manager, :config
|
11
12
|
|
@@ -29,16 +30,14 @@ module SplitIoClient
|
|
29
30
|
@splits_repository = SplitsRepository.new(@config)
|
30
31
|
@segments_repository = SegmentsRepository.new(@config)
|
31
32
|
@impressions_repository = ImpressionsRepository.new(@config)
|
32
|
-
@metrics_repository = MetricsRepository.new(@config)
|
33
33
|
@events_repository = EventsRepository.new(@config, @api_key)
|
34
|
-
|
34
|
+
@metrics_repository = MetricsRepository.new(@config)
|
35
35
|
@sdk_blocker = SDKBlocker.new(@splits_repository, @segments_repository, @config)
|
36
|
+
@metrics = Metrics.new(100, @metrics_repository)
|
36
37
|
|
37
|
-
|
38
|
+
start!
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
@client = SplitClient.new(@api_key, @adapter, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository, @events_repository, @sdk_blocker, @config, @sse_handler)
|
40
|
+
@client = SplitClient.new(@api_key, @metrics, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository, @events_repository, @sdk_blocker, @config)
|
42
41
|
@manager = SplitManager.new(@splits_repository, @sdk_blocker, @config)
|
43
42
|
|
44
43
|
validate_api_key
|
@@ -49,7 +48,11 @@ module SplitIoClient
|
|
49
48
|
end
|
50
49
|
|
51
50
|
def start!
|
52
|
-
|
51
|
+
if @config.localhost_mode
|
52
|
+
start_localhost_components
|
53
|
+
else
|
54
|
+
SplitIoClient::Engine::SyncManager.new(repositories, @api_key, @config, @sdk_blocker, @metrics).start
|
55
|
+
end
|
53
56
|
end
|
54
57
|
|
55
58
|
def stop!
|
@@ -118,15 +121,22 @@ module SplitIoClient
|
|
118
121
|
end
|
119
122
|
end
|
120
123
|
|
121
|
-
def
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
124
|
+
def repositories
|
125
|
+
repos = {}
|
126
|
+
repos[:splits] = @splits_repository
|
127
|
+
repos[:segments] = @segments_repository
|
128
|
+
repos[:impressions] = @impressions_repository
|
129
|
+
repos[:events] = @events_repository
|
130
|
+
repos[:metrics] = @metrics_repository
|
126
131
|
|
127
|
-
|
128
|
-
|
129
|
-
|
132
|
+
repos
|
133
|
+
end
|
134
|
+
|
135
|
+
def start_localhost_components
|
136
|
+
LocalhostSplitStore.new(@splits_repository, @config, @sdk_blocker).call
|
137
|
+
|
138
|
+
# Starts thread which loops constantly and cleans up repositories to avoid memory issues in localhost mode
|
139
|
+
LocalhostRepoCleaner.new(@impressions_repository, @metrics_repository, @events_repository, @config).call
|
130
140
|
end
|
131
141
|
end
|
132
142
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
module SplitIoClient
|
4
|
+
module SSE
|
5
|
+
module EventSource
|
6
|
+
class BackOff
|
7
|
+
def initialize(back_off_base)
|
8
|
+
@attempt = 0
|
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
|