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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +15 -0
  3. data/CHANGES.txt +6 -0
  4. data/lib/splitclient-rb.rb +24 -9
  5. data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +4 -0
  6. data/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb +21 -9
  7. data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +9 -9
  8. data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +6 -3
  9. data/lib/splitclient-rb/cache/repositories/events_repository.rb +4 -3
  10. data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +8 -0
  11. data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +2 -0
  12. data/lib/splitclient-rb/cache/repositories/repository.rb +0 -4
  13. data/lib/splitclient-rb/cache/repositories/segments_repository.rb +20 -0
  14. data/lib/splitclient-rb/cache/repositories/splits_repository.rb +4 -0
  15. data/lib/splitclient-rb/cache/senders/localhost_repo_cleaner.rb +1 -3
  16. data/lib/splitclient-rb/cache/stores/sdk_blocker.rb +9 -0
  17. data/lib/splitclient-rb/clients/split_client.rb +59 -25
  18. data/lib/splitclient-rb/constants.rb +6 -1
  19. data/lib/splitclient-rb/engine/api/client.rb +3 -2
  20. data/lib/splitclient-rb/engine/api/events.rb +10 -1
  21. data/lib/splitclient-rb/engine/api/impressions.rb +19 -2
  22. data/lib/splitclient-rb/engine/api/segments.rb +20 -18
  23. data/lib/splitclient-rb/engine/api/splits.rb +10 -10
  24. data/lib/splitclient-rb/engine/api/telemetry_api.rb +39 -0
  25. data/lib/splitclient-rb/engine/auth_api_client.rb +21 -8
  26. data/lib/splitclient-rb/engine/common/impressions_manager.rb +27 -3
  27. data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +3 -65
  28. data/lib/splitclient-rb/engine/push_manager.rb +12 -3
  29. data/lib/splitclient-rb/engine/sync_manager.rb +85 -46
  30. data/lib/splitclient-rb/engine/synchronizer.rb +14 -22
  31. data/lib/splitclient-rb/split_config.rb +46 -21
  32. data/lib/splitclient-rb/split_factory.rb +31 -13
  33. data/lib/splitclient-rb/split_factory_registry.rb +12 -0
  34. data/lib/splitclient-rb/sse/event_source/client.rb +53 -28
  35. data/lib/splitclient-rb/sse/event_source/event_parser.rb +10 -1
  36. data/lib/splitclient-rb/sse/notification_manager_keeper.rb +45 -26
  37. data/lib/splitclient-rb/sse/sse_handler.rb +16 -21
  38. data/lib/splitclient-rb/sse/workers/segments_worker.rb +5 -4
  39. data/lib/splitclient-rb/sse/workers/splits_worker.rb +6 -3
  40. data/lib/splitclient-rb/telemetry/domain/constants.rb +42 -0
  41. data/lib/splitclient-rb/telemetry/domain/structs.rb +31 -0
  42. data/lib/splitclient-rb/telemetry/evaluation_consumer.rb +14 -0
  43. data/lib/splitclient-rb/telemetry/evaluation_producer.rb +21 -0
  44. data/lib/splitclient-rb/telemetry/init_consumer.rb +14 -0
  45. data/lib/splitclient-rb/telemetry/init_producer.rb +19 -0
  46. data/lib/splitclient-rb/telemetry/memory/memory_evaluation_consumer.rb +32 -0
  47. data/lib/splitclient-rb/telemetry/memory/memory_evaluation_producer.rb +24 -0
  48. data/lib/splitclient-rb/telemetry/memory/memory_init_consumer.rb +28 -0
  49. data/lib/splitclient-rb/telemetry/memory/memory_init_producer.rb +34 -0
  50. data/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb +112 -0
  51. data/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb +81 -0
  52. data/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb +192 -0
  53. data/lib/splitclient-rb/telemetry/redis/redis_evaluation_producer.rb +38 -0
  54. data/lib/splitclient-rb/telemetry/redis/redis_init_producer.rb +37 -0
  55. data/lib/splitclient-rb/telemetry/redis/redis_synchronizer.rb +28 -0
  56. data/lib/splitclient-rb/telemetry/runtime_consumer.rb +24 -0
  57. data/lib/splitclient-rb/telemetry/runtime_producer.rb +24 -0
  58. data/lib/splitclient-rb/telemetry/storages/memory.rb +139 -0
  59. data/lib/splitclient-rb/telemetry/sync_task.rb +38 -0
  60. data/lib/splitclient-rb/telemetry/synchronizer.rb +29 -0
  61. data/lib/splitclient-rb/version.rb +1 -1
  62. metadata +24 -9
  63. data/lib/splitclient-rb/cache/repositories/metrics/memory_repository.rb +0 -163
  64. data/lib/splitclient-rb/cache/repositories/metrics/redis_repository.rb +0 -131
  65. data/lib/splitclient-rb/cache/repositories/metrics_repository.rb +0 -23
  66. data/lib/splitclient-rb/cache/senders/metrics_sender.rb +0 -55
  67. data/lib/splitclient-rb/engine/api/metrics.rb +0 -61
  68. data/lib/splitclient-rb/engine/metrics/metrics.rb +0 -80
  69. 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
- back_off = SplitIoClient::SSE::EventSource::BackOff.new(SplitIoClient::Constants::FETCH_BACK_OFF_BASE_RETRIES, 1)
57
- loop do
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
- back_off = SplitIoClient::SSE::EventSource::BackOff.new(SplitIoClient::Constants::FETCH_BACK_OFF_BASE_RETRIES, 1)
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, @metrics, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository, @events_repository, @sdk_blocker, @config, @impressions_manager)
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, @metrics, config, @sdk_blocker)
58
- segment_fetcher = SegmentFetcher.new(@segments_repository, @api_key, @metrics, config, @sdk_blocker)
59
- params = { split_fetcher: split_fetcher, segment_fetcher: segment_fetcher, imp_counter: @impression_counter }
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, @metrics_repository, @events_repository, @config).call
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: ->(_) {}, connected: ->(_) {}, disconnect: ->(_) {} }
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 on_connected(&action)
31
- @on[:connected] = action
34
+ def on_action(&action)
35
+ @on[:action] = action
32
36
  end
33
37
 
34
- def on_disconnect(&action)
35
- @on[:disconnect] = action
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(latch)
80
+ socket_write
76
81
 
77
- while @connected.value
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(true) # close conexion & reconnect
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(latch)
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
- ensure
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(true) # close conexion & reconnect
171
+ close(Constants::PUSH_RETRYABLE_ERROR)
141
172
  elsif event.data['code'] >= 40_000 && event.data['code'] <= 49_999
142
- close # close conexion
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 dispatch_connected
152
- @connected.make_true
153
- @config.logger.debug('Dispatching connected') if @config.debug_enabled
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