splitclient-rb 7.2.2.pre.rc1-java → 7.3.0.pre.rc2-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +15 -0
- data/CHANGES.txt +6 -0
- data/lib/splitclient-rb.rb +24 -9
- data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +4 -0
- data/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb +21 -9
- data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +9 -9
- data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +6 -3
- data/lib/splitclient-rb/cache/repositories/events_repository.rb +4 -3
- data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +8 -0
- data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +2 -0
- data/lib/splitclient-rb/cache/repositories/repository.rb +0 -4
- data/lib/splitclient-rb/cache/repositories/segments_repository.rb +20 -0
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +4 -0
- data/lib/splitclient-rb/cache/senders/localhost_repo_cleaner.rb +1 -3
- data/lib/splitclient-rb/cache/stores/sdk_blocker.rb +9 -0
- data/lib/splitclient-rb/clients/split_client.rb +59 -25
- data/lib/splitclient-rb/constants.rb +6 -1
- data/lib/splitclient-rb/engine/api/client.rb +3 -2
- data/lib/splitclient-rb/engine/api/events.rb +10 -1
- data/lib/splitclient-rb/engine/api/impressions.rb +19 -2
- data/lib/splitclient-rb/engine/api/segments.rb +20 -18
- data/lib/splitclient-rb/engine/api/splits.rb +10 -10
- data/lib/splitclient-rb/engine/api/telemetry_api.rb +39 -0
- data/lib/splitclient-rb/engine/auth_api_client.rb +21 -8
- data/lib/splitclient-rb/engine/common/impressions_manager.rb +27 -3
- data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +3 -65
- data/lib/splitclient-rb/engine/push_manager.rb +12 -3
- data/lib/splitclient-rb/engine/sync_manager.rb +85 -46
- data/lib/splitclient-rb/engine/synchronizer.rb +14 -22
- data/lib/splitclient-rb/split_config.rb +46 -21
- data/lib/splitclient-rb/split_factory.rb +31 -13
- data/lib/splitclient-rb/split_factory_registry.rb +12 -0
- data/lib/splitclient-rb/sse/event_source/client.rb +53 -28
- data/lib/splitclient-rb/sse/event_source/event_parser.rb +10 -1
- data/lib/splitclient-rb/sse/notification_manager_keeper.rb +45 -26
- data/lib/splitclient-rb/sse/sse_handler.rb +16 -21
- data/lib/splitclient-rb/sse/workers/segments_worker.rb +5 -4
- data/lib/splitclient-rb/sse/workers/splits_worker.rb +6 -3
- data/lib/splitclient-rb/telemetry/domain/constants.rb +42 -0
- data/lib/splitclient-rb/telemetry/domain/structs.rb +31 -0
- data/lib/splitclient-rb/telemetry/evaluation_consumer.rb +14 -0
- data/lib/splitclient-rb/telemetry/evaluation_producer.rb +21 -0
- data/lib/splitclient-rb/telemetry/init_consumer.rb +14 -0
- data/lib/splitclient-rb/telemetry/init_producer.rb +19 -0
- data/lib/splitclient-rb/telemetry/memory/memory_evaluation_consumer.rb +32 -0
- data/lib/splitclient-rb/telemetry/memory/memory_evaluation_producer.rb +24 -0
- data/lib/splitclient-rb/telemetry/memory/memory_init_consumer.rb +28 -0
- data/lib/splitclient-rb/telemetry/memory/memory_init_producer.rb +34 -0
- data/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb +112 -0
- data/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb +81 -0
- data/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb +192 -0
- data/lib/splitclient-rb/telemetry/redis/redis_evaluation_producer.rb +38 -0
- data/lib/splitclient-rb/telemetry/redis/redis_init_producer.rb +37 -0
- data/lib/splitclient-rb/telemetry/redis/redis_synchronizer.rb +28 -0
- data/lib/splitclient-rb/telemetry/runtime_consumer.rb +24 -0
- data/lib/splitclient-rb/telemetry/runtime_producer.rb +24 -0
- data/lib/splitclient-rb/telemetry/storages/memory.rb +139 -0
- data/lib/splitclient-rb/telemetry/sync_task.rb +38 -0
- data/lib/splitclient-rb/telemetry/synchronizer.rb +29 -0
- data/lib/splitclient-rb/version.rb +1 -1
- metadata +24 -9
- data/lib/splitclient-rb/cache/repositories/metrics/memory_repository.rb +0 -163
- data/lib/splitclient-rb/cache/repositories/metrics/redis_repository.rb +0 -131
- data/lib/splitclient-rb/cache/repositories/metrics_repository.rb +0 -23
- data/lib/splitclient-rb/cache/senders/metrics_sender.rb +0 -55
- data/lib/splitclient-rb/engine/api/metrics.rb +0 -61
- data/lib/splitclient-rb/engine/metrics/metrics.rb +0 -80
- data/lib/splitclient-rb/redis_metrics_fixer.rb +0 -36
@@ -6,6 +6,8 @@ module SplitIoClient
|
|
6
6
|
include SplitIoClient::Cache::Fetchers
|
7
7
|
include SplitIoClient::Cache::Senders
|
8
8
|
|
9
|
+
FORCE_CACHE_CONTROL_HEADERS = true
|
10
|
+
|
9
11
|
def initialize(
|
10
12
|
repositories,
|
11
13
|
api_key,
|
@@ -16,30 +18,30 @@ module SplitIoClient
|
|
16
18
|
@splits_repository = repositories[:splits]
|
17
19
|
@segments_repository = repositories[:segments]
|
18
20
|
@impressions_repository = repositories[:impressions]
|
19
|
-
@metrics_repository = repositories[:metrics]
|
20
21
|
@events_repository = repositories[:events]
|
21
22
|
@api_key = api_key
|
22
23
|
@config = config
|
23
24
|
@sdk_blocker = sdk_blocker
|
24
25
|
@split_fetcher = params[:split_fetcher]
|
25
26
|
@segment_fetcher = params[:segment_fetcher]
|
26
|
-
@impressions_api = SplitIoClient::Api::Impressions.new(@api_key, @config)
|
27
|
+
@impressions_api = SplitIoClient::Api::Impressions.new(@api_key, @config, params[:telemetry_runtime_producer])
|
27
28
|
@impression_counter = params[:imp_counter]
|
29
|
+
@telemetry_synchronizer = params[:telemetry_synchronizer]
|
28
30
|
end
|
29
31
|
|
30
32
|
def sync_all
|
31
33
|
@config.threads[:sync_all_thread] = Thread.new do
|
32
34
|
@config.logger.debug('Synchronizing Splits and Segments ...') if @config.debug_enabled
|
33
|
-
fetch_splits
|
34
|
-
fetch_segments
|
35
|
+
@split_fetcher.fetch_splits
|
36
|
+
@segment_fetcher.fetch_segments
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
38
40
|
def start_periodic_data_recording
|
39
41
|
impressions_sender
|
40
|
-
metrics_sender
|
41
42
|
events_sender
|
42
43
|
impressions_count_sender
|
44
|
+
start_telemetry_sync_task
|
43
45
|
end
|
44
46
|
|
45
47
|
def start_periodic_fetch
|
@@ -53,21 +55,12 @@ module SplitIoClient
|
|
53
55
|
end
|
54
56
|
|
55
57
|
def fetch_splits
|
56
|
-
|
57
|
-
|
58
|
-
break if @split_fetcher.fetch_splits
|
59
|
-
|
60
|
-
sleep(back_off.interval)
|
61
|
-
end
|
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?
|
62
60
|
end
|
63
61
|
|
64
62
|
def fetch_segment(name)
|
65
|
-
|
66
|
-
loop do
|
67
|
-
break if @segment_fetcher.fetch_segment(name)
|
68
|
-
|
69
|
-
sleep(back_off.interval)
|
70
|
-
end
|
63
|
+
@segment_fetcher.fetch_segment(name, FORCE_CACHE_CONTROL_HEADERS)
|
71
64
|
end
|
72
65
|
|
73
66
|
private
|
@@ -81,11 +74,6 @@ module SplitIoClient
|
|
81
74
|
ImpressionsSender.new(@impressions_repository, @config, @impressions_api).call
|
82
75
|
end
|
83
76
|
|
84
|
-
# Starts thread which loops constantly and sends metrics to the Split API
|
85
|
-
def metrics_sender
|
86
|
-
MetricsSender.new(@metrics_repository, @api_key, @config).call
|
87
|
-
end
|
88
|
-
|
89
77
|
# Starts thread which loops constantly and sends events to the Split API
|
90
78
|
def events_sender
|
91
79
|
EventsSender.new(@events_repository, @config).call
|
@@ -95,6 +83,10 @@ module SplitIoClient
|
|
95
83
|
def impressions_count_sender
|
96
84
|
ImpressionsCountSender.new(@config, @impression_counter, @impressions_api).call
|
97
85
|
end
|
86
|
+
|
87
|
+
def start_telemetry_sync_task
|
88
|
+
Telemetry::SyncTask.new(@config, @telemetry_synchronizer).call
|
89
|
+
end
|
98
90
|
end
|
99
91
|
end
|
100
92
|
end
|
@@ -17,7 +17,6 @@ module SplitIoClient
|
|
17
17
|
# @option opts [Int] :connection_timeout (2) The connect timeout for network connections in seconds.
|
18
18
|
# @option opts [Int] :features_refresh_rate The SDK polls Split servers for changes to feature roll-out plans. This parameter controls this polling period in seconds.
|
19
19
|
# @option opts [Int] :segments_refresh_rate
|
20
|
-
# @option opts [Int] :metrics_refresh_rate
|
21
20
|
# @option opts [Int] :impressions_refresh_rate
|
22
21
|
# @option opts [Object] :logger a logger to user for messages from the client. Defaults to stdout
|
23
22
|
# @option opts [Boolean] :debug_enabled (false) The value for the debug flag
|
@@ -51,7 +50,6 @@ module SplitIoClient
|
|
51
50
|
end
|
52
51
|
|
53
52
|
@segments_refresh_rate = opts[:segments_refresh_rate] || SplitConfig.default_segments_refresh_rate
|
54
|
-
@metrics_refresh_rate = opts[:metrics_refresh_rate] || SplitConfig.default_metrics_refresh_rate
|
55
53
|
|
56
54
|
@impressions_mode = init_impressions_mode(opts[:impressions_mode])
|
57
55
|
|
@@ -63,10 +61,6 @@ module SplitIoClient
|
|
63
61
|
#Safeguard for users of older SDK versions.
|
64
62
|
@impressions_bulk_size = opts[:impressions_bulk_size] || @impressions_queue_size > 0 ? @impressions_queue_size : 0
|
65
63
|
|
66
|
-
@metrics_adapter = SplitConfig.init_cache_adapter(
|
67
|
-
opts[:cache_adapter] || SplitConfig.default_cache_adapter, :map_adapter, nil, @redis_url
|
68
|
-
)
|
69
|
-
|
70
64
|
@debug_enabled = opts[:debug_enabled] || SplitConfig.default_debug
|
71
65
|
@transport_debug_enabled = opts[:transport_debug_enabled] || SplitConfig.default_debug
|
72
66
|
@block_until_ready = SplitConfig.default_block_until_ready
|
@@ -97,6 +91,10 @@ module SplitIoClient
|
|
97
91
|
opts[:cache_adapter] || SplitConfig.default_cache_adapter, :queue_adapter, @events_queue_size, @redis_url
|
98
92
|
)
|
99
93
|
|
94
|
+
@telemetry_adapter = SplitConfig.init_telemetry_adapter(
|
95
|
+
opts[:cache_adapter] || SplitConfig.default_cache_adapter, @redis_url
|
96
|
+
)
|
97
|
+
|
100
98
|
@split_file = opts[:split_file] || SplitConfig.default_split_file
|
101
99
|
|
102
100
|
@valid_mode = true
|
@@ -110,6 +108,11 @@ module SplitIoClient
|
|
110
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)
|
111
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)
|
112
110
|
|
111
|
+
@telemetry_refresh_rate = SplitConfig.init_telemetry_refresh_rate(opts[:telemetry_refresh_rate])
|
112
|
+
@telemetry_service_url = opts[:telemetry_service_url] || SplitConfig.default_telemetry_service_url
|
113
|
+
|
114
|
+
@sdk_start_time = Time.now
|
115
|
+
|
113
116
|
startup_log
|
114
117
|
end
|
115
118
|
|
@@ -148,12 +151,6 @@ module SplitIoClient
|
|
148
151
|
# @return [Object] Impressions adapter instance
|
149
152
|
attr_accessor :impressions_adapter
|
150
153
|
|
151
|
-
#
|
152
|
-
# The cache adapter to store metrics in
|
153
|
-
#
|
154
|
-
# @return [Symbol] Metrics adapter
|
155
|
-
attr_accessor :metrics_adapter
|
156
|
-
|
157
154
|
#
|
158
155
|
# The cache adapter to store events in
|
159
156
|
#
|
@@ -224,7 +221,6 @@ module SplitIoClient
|
|
224
221
|
|
225
222
|
attr_accessor :features_refresh_rate
|
226
223
|
attr_accessor :segments_refresh_rate
|
227
|
-
attr_accessor :metrics_refresh_rate
|
228
224
|
attr_accessor :impressions_refresh_rate
|
229
225
|
|
230
226
|
attr_accessor :impression_listener
|
@@ -274,6 +270,14 @@ module SplitIoClient
|
|
274
270
|
|
275
271
|
attr_accessor :impressions_mode
|
276
272
|
|
273
|
+
attr_accessor :telemetry_adapter
|
274
|
+
|
275
|
+
attr_accessor :telemetry_refresh_rate
|
276
|
+
|
277
|
+
attr_accessor :telemetry_service_url
|
278
|
+
|
279
|
+
attr_accessor :sdk_start_time
|
280
|
+
|
277
281
|
def self.default_impressions_mode
|
278
282
|
:optimized
|
279
283
|
end
|
@@ -296,6 +300,12 @@ module SplitIoClient
|
|
296
300
|
return refresh_rate.nil? || refresh_rate <= 0 ? SplitConfig.default_impressions_refresh_rate_optimized : [default_rate, refresh_rate].max
|
297
301
|
end
|
298
302
|
|
303
|
+
def self.init_telemetry_refresh_rate(refresh_rate)
|
304
|
+
return SplitConfig.default_telemetry_refresh_rate if refresh_rate.nil? || refresh_rate < 60
|
305
|
+
|
306
|
+
refresh_rate
|
307
|
+
end
|
308
|
+
|
299
309
|
def self.default_streaming_enabled
|
300
310
|
true
|
301
311
|
end
|
@@ -359,6 +369,21 @@ module SplitIoClient
|
|
359
369
|
end
|
360
370
|
end
|
361
371
|
|
372
|
+
def self.init_telemetry_adapter(adapter, redis_url)
|
373
|
+
case adapter
|
374
|
+
when :memory
|
375
|
+
Telemetry::Storages::Memory.new
|
376
|
+
when :redis
|
377
|
+
begin
|
378
|
+
require 'redis'
|
379
|
+
rescue LoadError
|
380
|
+
fail StandardError, 'To use Redis as a cache adapter you must include it in your Gemfile'
|
381
|
+
end
|
382
|
+
|
383
|
+
SplitIoClient::Cache::Adapters::RedisAdapter.new(redis_url)
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
362
387
|
def self.map_memory_adapter(name, queue_size)
|
363
388
|
case name
|
364
389
|
when :map_adapter
|
@@ -377,10 +402,6 @@ module SplitIoClient
|
|
377
402
|
:memory
|
378
403
|
end
|
379
404
|
|
380
|
-
def self.default_metrics_adapter
|
381
|
-
:memory
|
382
|
-
end
|
383
|
-
|
384
405
|
#
|
385
406
|
# The default read timeout value
|
386
407
|
#
|
@@ -405,10 +426,6 @@ module SplitIoClient
|
|
405
426
|
60
|
406
427
|
end
|
407
428
|
|
408
|
-
def self.default_metrics_refresh_rate
|
409
|
-
60
|
410
|
-
end
|
411
|
-
|
412
429
|
def self.default_impressions_refresh_rate
|
413
430
|
60
|
414
431
|
end
|
@@ -433,6 +450,14 @@ module SplitIoClient
|
|
433
450
|
500
|
434
451
|
end
|
435
452
|
|
453
|
+
def self.default_telemetry_refresh_rate
|
454
|
+
3600
|
455
|
+
end
|
456
|
+
|
457
|
+
def self.default_telemetry_service_url
|
458
|
+
'https://telemetry.split.io/api/v1'
|
459
|
+
end
|
460
|
+
|
436
461
|
def self.default_split_file
|
437
462
|
File.join(Dir.home, '.split')
|
438
463
|
end
|
@@ -28,25 +28,25 @@ module SplitIoClient
|
|
28
28
|
|
29
29
|
raise 'Invalid SDK mode' unless valid_mode
|
30
30
|
|
31
|
+
build_telemetry_components
|
32
|
+
|
31
33
|
@splits_repository = SplitsRepository.new(@config)
|
32
34
|
@segments_repository = SegmentsRepository.new(@config)
|
33
35
|
@impressions_repository = ImpressionsRepository.new(@config)
|
34
|
-
@events_repository = EventsRepository.new(@config, @api_key)
|
35
|
-
@metrics_repository = MetricsRepository.new(@config)
|
36
|
+
@events_repository = EventsRepository.new(@config, @api_key, @runtime_producer)
|
36
37
|
@sdk_blocker = SDKBlocker.new(@splits_repository, @segments_repository, @config)
|
37
|
-
@metrics = Metrics.new(100, @metrics_repository)
|
38
38
|
@impression_counter = SplitIoClient::Engine::Common::ImpressionCounter.new
|
39
|
-
@impressions_manager = SplitIoClient::Engine::Common::ImpressionManager.new(@config, @impressions_repository, @impression_counter)
|
39
|
+
@impressions_manager = SplitIoClient::Engine::Common::ImpressionManager.new(@config, @impressions_repository, @impression_counter, @runtime_producer)
|
40
|
+
@telemetry_api = SplitIoClient::Api::TelemetryApi.new(@config, @api_key, @runtime_producer)
|
41
|
+
@telemetry_synchronizer = Telemetry::Synchronizer.new(@config, @telemetry_consumers, @init_producer, repositories, @telemetry_api)
|
40
42
|
|
41
43
|
start!
|
42
44
|
|
43
|
-
@client = SplitClient.new(@api_key,
|
45
|
+
@client = SplitClient.new(@api_key, repositories, @sdk_blocker, @config, @impressions_manager, @evaluation_producer)
|
44
46
|
@manager = SplitManager.new(@splits_repository, @sdk_blocker, @config)
|
45
47
|
|
46
48
|
validate_api_key
|
47
49
|
|
48
|
-
RedisMetricsFixer.new(@metrics_repository, @config).call
|
49
|
-
|
50
50
|
register_factory
|
51
51
|
end
|
52
52
|
|
@@ -54,12 +54,18 @@ module SplitIoClient
|
|
54
54
|
if @config.localhost_mode
|
55
55
|
start_localhost_components
|
56
56
|
else
|
57
|
-
split_fetcher = SplitFetcher.new(@splits_repository, @api_key,
|
58
|
-
segment_fetcher = SegmentFetcher.new(@segments_repository, @api_key,
|
59
|
-
params = {
|
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
|
+
}
|
60
66
|
|
61
67
|
synchronizer = SplitIoClient::Engine::Synchronizer.new(repositories, @api_key, @config, @sdk_blocker, params)
|
62
|
-
SplitIoClient::Engine::SyncManager.new(repositories, @api_key, @config, synchronizer).start
|
68
|
+
SplitIoClient::Engine::SyncManager.new(repositories, @api_key, @config, synchronizer, @runtime_producer, @sdk_blocker, @telemetry_synchronizer).start
|
63
69
|
end
|
64
70
|
end
|
65
71
|
|
@@ -135,7 +141,6 @@ module SplitIoClient
|
|
135
141
|
segments: @segments_repository,
|
136
142
|
impressions: @impressions_repository,
|
137
143
|
events: @events_repository,
|
138
|
-
metrics: @metrics_repository
|
139
144
|
}
|
140
145
|
end
|
141
146
|
|
@@ -143,7 +148,20 @@ module SplitIoClient
|
|
143
148
|
LocalhostSplitStore.new(@splits_repository, @config, @sdk_blocker).call
|
144
149
|
|
145
150
|
# Starts thread which loops constantly and cleans up repositories to avoid memory issues in localhost mode
|
146
|
-
LocalhostRepoCleaner.new(@impressions_repository, @
|
151
|
+
LocalhostRepoCleaner.new(@impressions_repository, @events_repository, @config).call
|
147
152
|
end
|
153
|
+
|
154
|
+
def build_telemetry_components
|
155
|
+
@evaluation_consumer = Telemetry::EvaluationConsumer.new(@config)
|
156
|
+
@evaluation_producer = Telemetry::EvaluationProducer.new(@config)
|
157
|
+
|
158
|
+
@init_consumer = Telemetry::InitConsumer.new(@config)
|
159
|
+
@init_producer = Telemetry::InitProducer.new(@config)
|
160
|
+
|
161
|
+
@runtime_consumer = Telemetry::RuntimeConsumer.new(@config)
|
162
|
+
@runtime_producer = Telemetry::RuntimeProducer.new(@config)
|
163
|
+
|
164
|
+
@telemetry_consumers = { init: @init_consumer, evaluation: @evaluation_consumer, runtime: @runtime_consumer }
|
165
|
+
end
|
148
166
|
end
|
149
167
|
end
|
@@ -47,5 +47,17 @@ module SplitIoClient
|
|
47
47
|
def other_factories
|
48
48
|
return !@api_keys_hash.empty?
|
49
49
|
end
|
50
|
+
|
51
|
+
def active_factories
|
52
|
+
@api_keys_hash.length
|
53
|
+
end
|
54
|
+
|
55
|
+
def redundant_active_factories
|
56
|
+
to_return = 0
|
57
|
+
|
58
|
+
@api_keys_hash.each { |key| to_return += (key[1]-1) }
|
59
|
+
|
60
|
+
to_return
|
61
|
+
end
|
50
62
|
end
|
51
63
|
end
|
@@ -9,16 +9,20 @@ module SplitIoClient
|
|
9
9
|
class Client
|
10
10
|
DEFAULT_READ_TIMEOUT = 70
|
11
11
|
CONNECT_TIMEOUT = 30_000
|
12
|
+
OK_CODE = 200
|
12
13
|
KEEP_ALIVE_RESPONSE = "c\r\n:keepalive\n\n\r\n".freeze
|
13
14
|
ERROR_EVENT_TYPE = 'error'.freeze
|
14
15
|
|
15
|
-
def initialize(config, read_timeout: DEFAULT_READ_TIMEOUT)
|
16
|
+
def initialize(config, api_key, telemetry_runtime_producer, read_timeout: DEFAULT_READ_TIMEOUT)
|
16
17
|
@config = config
|
17
18
|
@read_timeout = read_timeout
|
18
19
|
@connected = Concurrent::AtomicBoolean.new(false)
|
20
|
+
@first_event = Concurrent::AtomicBoolean.new(true)
|
19
21
|
@socket = nil
|
20
22
|
@event_parser = SSE::EventSource::EventParser.new(config)
|
21
|
-
@on = { event: ->(_) {},
|
23
|
+
@on = { event: ->(_) {}, action: ->(_) {} }
|
24
|
+
@api_key = api_key
|
25
|
+
@telemetry_runtime_producer = telemetry_runtime_producer
|
22
26
|
|
23
27
|
yield self if block_given?
|
24
28
|
end
|
@@ -27,16 +31,12 @@ module SplitIoClient
|
|
27
31
|
@on[:event] = action
|
28
32
|
end
|
29
33
|
|
30
|
-
def
|
31
|
-
@on[:
|
34
|
+
def on_action(&action)
|
35
|
+
@on[:action] = action
|
32
36
|
end
|
33
37
|
|
34
|
-
def
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
def close(reconnect = false)
|
39
|
-
dispatch_disconnect(reconnect)
|
38
|
+
def close(action = Constants::PUSH_NONRETRYABLE_ERROR)
|
39
|
+
dispatch_action(action)
|
40
40
|
@connected.make_false
|
41
41
|
SplitIoClient::Helpers::ThreadHelper.stop(:connect_stream, @config)
|
42
42
|
@socket&.close
|
@@ -45,6 +45,11 @@ module SplitIoClient
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def start(url)
|
48
|
+
if connected?
|
49
|
+
@config.logger.debug('SSEClient already running.')
|
50
|
+
return true
|
51
|
+
end
|
52
|
+
|
48
53
|
@uri = URI(url)
|
49
54
|
latch = Concurrent::CountDownLatch.new(1)
|
50
55
|
|
@@ -72,16 +77,18 @@ module SplitIoClient
|
|
72
77
|
end
|
73
78
|
|
74
79
|
def connect_stream(latch)
|
75
|
-
socket_write
|
80
|
+
socket_write
|
76
81
|
|
77
|
-
while @
|
82
|
+
while connected? || @first_event.value
|
78
83
|
begin
|
79
84
|
partial_data = @socket.readpartial(10_000, timeout: @read_timeout)
|
80
85
|
|
86
|
+
read_first_event(partial_data, latch)
|
87
|
+
|
81
88
|
raise 'eof exception' if partial_data == :eof
|
82
89
|
rescue StandardError => e
|
83
90
|
@config.logger.error('Error reading partial data: ' + e.inspect) if @config.debug_enabled
|
84
|
-
close(
|
91
|
+
close(Constants::PUSH_RETRYABLE_ERROR)
|
85
92
|
return
|
86
93
|
end
|
87
94
|
|
@@ -89,14 +96,32 @@ module SplitIoClient
|
|
89
96
|
end
|
90
97
|
end
|
91
98
|
|
92
|
-
def socket_write
|
99
|
+
def socket_write
|
100
|
+
@first_event.make_true
|
93
101
|
@socket = socket_connect
|
94
102
|
@socket.write(build_request(@uri))
|
95
|
-
dispatch_connected
|
96
103
|
rescue StandardError => e
|
97
104
|
@config.logger.error("Error during connecting to #{@uri.host}. Error: #{e.inspect}")
|
98
|
-
close
|
99
|
-
|
105
|
+
close(Constants::PUSH_NONRETRYABLE_ERROR)
|
106
|
+
end
|
107
|
+
|
108
|
+
def read_first_event(data, latch)
|
109
|
+
return unless @first_event.value
|
110
|
+
|
111
|
+
response_code = @event_parser.first_event(data)
|
112
|
+
@config.logger.debug("SSE client first event code: #{response_code}")
|
113
|
+
|
114
|
+
error_event = false
|
115
|
+
events = @event_parser.parse(data)
|
116
|
+
events.each { |e| error_event = true if e.event_type == ERROR_EVENT_TYPE }
|
117
|
+
@first_event.make_false
|
118
|
+
|
119
|
+
if response_code == OK_CODE && !error_event
|
120
|
+
@connected.make_true
|
121
|
+
@telemetry_runtime_producer.record_streaming_event(Telemetry::Domain::Constants::SSE_CONNECTION_ESTABLISHED, nil)
|
122
|
+
dispatch_action(Constants::PUSH_CONNECTED)
|
123
|
+
end
|
124
|
+
|
100
125
|
latch.count_down
|
101
126
|
end
|
102
127
|
|
@@ -120,6 +145,10 @@ module SplitIoClient
|
|
120
145
|
req = "GET #{uri.request_uri} HTTP/1.1\r\n"
|
121
146
|
req << "Host: #{uri.host}\r\n"
|
122
147
|
req << "Accept: text/event-stream\r\n"
|
148
|
+
req << "SplitSDKVersion: #{@config.language}-#{@config.version}\r\n"
|
149
|
+
req << "SplitSDKMachineIP: #{@config.machine_ip}\r\n"
|
150
|
+
req << "SplitSDKMachineName: #{@config.machine_name}\r\n"
|
151
|
+
req << "SplitSDKClientKey: #{@api_key.split(//).last(4).join}\r\n" unless @api_key.nil?
|
123
152
|
req << "Cache-Control: no-cache\r\n\r\n"
|
124
153
|
@config.logger.debug("Request info: #{req}") if @config.debug_enabled
|
125
154
|
req
|
@@ -136,10 +165,12 @@ module SplitIoClient
|
|
136
165
|
|
137
166
|
def dispatch_error(event)
|
138
167
|
@config.logger.error("Event error: #{event.event_type}, #{event.data}")
|
168
|
+
@telemetry_runtime_producer.record_streaming_event(Telemetry::Domain::Constants::ABLY_ERROR, event.data['code'])
|
169
|
+
|
139
170
|
if event.data['code'] >= 40_140 && event.data['code'] <= 40_149
|
140
|
-
close(
|
171
|
+
close(Constants::PUSH_RETRYABLE_ERROR)
|
141
172
|
elsif event.data['code'] >= 40_000 && event.data['code'] <= 49_999
|
142
|
-
close
|
173
|
+
close(Constants::PUSH_NONRETRYABLE_ERROR)
|
143
174
|
end
|
144
175
|
end
|
145
176
|
|
@@ -148,15 +179,9 @@ module SplitIoClient
|
|
148
179
|
@on[:event].call(event)
|
149
180
|
end
|
150
181
|
|
151
|
-
def
|
152
|
-
@
|
153
|
-
@
|
154
|
-
@on[:connected].call
|
155
|
-
end
|
156
|
-
|
157
|
-
def dispatch_disconnect(reconnect)
|
158
|
-
@config.logger.debug('Dispatching disconnect') if @config.debug_enabled
|
159
|
-
@on[:disconnect].call(reconnect)
|
182
|
+
def dispatch_action(action)
|
183
|
+
@config.logger.debug("Dispatching action: #{action}") if @config.debug_enabled
|
184
|
+
@on[:action].call(action)
|
160
185
|
end
|
161
186
|
end
|
162
187
|
end
|