splitclient-rb 7.2.2-java → 7.3.0.pre.rc1-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 +16 -7
  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 +26 -11
  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
@@ -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
@@ -4,6 +4,8 @@ module SplitIoClient
4
4
  module SSE
5
5
  module EventSource
6
6
  class EventParser
7
+ BAD_REQUEST_CODE = 400
8
+
7
9
  def initialize(config)
8
10
  @config = config
9
11
  end
@@ -27,10 +29,17 @@ module SplitIoClient
27
29
 
28
30
  events
29
31
  rescue StandardError => e
30
- @config.logger.error("Error during parsing a event: #{e.inspect}")
32
+ @config.logger.debug("Error during parsing a event: #{e.inspect}")
31
33
  []
32
34
  end
33
35
 
36
+ def first_event(raw_data)
37
+ raw_data.split("\n")[0].split(' ')[1].to_i
38
+ rescue StandardError => e
39
+ @config.logger.debug("Error parsing first event: #{e.inspect}")
40
+ BAD_REQUEST_CODE
41
+ end
42
+
34
43
  private
35
44
 
36
45
  def parse_event_data(data, type)
@@ -1,14 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'concurrent/atomics'
3
+ require 'concurrent'
4
4
 
5
5
  module SplitIoClient
6
6
  module SSE
7
7
  class NotificationManagerKeeper
8
- def initialize(config)
8
+ DISABLED = 0
9
+ ENABLED = 1
10
+ PAUSED = 2
11
+
12
+ def initialize(config, telemetry_runtime_producer)
9
13
  @config = config
10
14
  @publisher_available = Concurrent::AtomicBoolean.new(true)
11
- @on = { occupancy: ->(_) {}, push_shutdown: ->(_) {} }
15
+ @publishers_pri = Concurrent::AtomicFixnum.new
16
+ @publishers_sec = Concurrent::AtomicFixnum.new
17
+ @on = { action: ->(_) {} }
18
+ @telemetry_runtime_producer = telemetry_runtime_producer
12
19
 
13
20
  yield self if block_given?
14
21
  end
@@ -16,19 +23,16 @@ module SplitIoClient
16
23
  def handle_incoming_occupancy_event(event)
17
24
  if event.data['type'] == 'CONTROL'
18
25
  process_event_control(event.data['controlType'])
19
- elsif event.channel == SplitIoClient::Constants::CONTROL_PRI
20
- process_event_occupancy(event.data['metrics']['publishers'])
26
+ else
27
+ process_event_occupancy(event.channel, event.data['metrics']['publishers'])
21
28
  end
22
29
  rescue StandardError => e
30
+ p e
23
31
  @config.logger.error(e)
24
32
  end
25
33
 
26
- def on_occupancy(&action)
27
- @on[:occupancy] = action
28
- end
29
-
30
- def on_push_shutdown(&action)
31
- @on[:push_shutdown] = action
34
+ def on_action(&action)
35
+ @on[:action] = action
32
36
  end
33
37
 
34
38
  private
@@ -36,35 +40,50 @@ module SplitIoClient
36
40
  def process_event_control(type)
37
41
  case type
38
42
  when 'STREAMING_PAUSED'
39
- dispatch_occupancy_event(false)
43
+ @telemetry_runtime_producer.record_streaming_event(Telemetry::Domain::Constants::STREAMING_STATUS, PAUSED)
44
+ dispatch_action(Constants::PUSH_SUBSYSTEM_DOWN)
40
45
  when 'STREAMING_RESUMED'
41
- dispatch_occupancy_event(true) if @publisher_available.value
46
+ @telemetry_runtime_producer.record_streaming_event(Telemetry::Domain::Constants::STREAMING_STATUS, ENABLED)
47
+ dispatch_action(Constants::PUSH_SUBSYSTEM_READY) if @publisher_available.value
42
48
  when 'STREAMING_DISABLED'
43
- dispatch_push_shutdown
49
+ @telemetry_runtime_producer.record_streaming_event(Telemetry::Domain::Constants::STREAMING_STATUS, DISABLED)
50
+ dispatch_action(Constants::PUSH_SUBSYSTEM_OFF)
44
51
  else
45
52
  @config.logger.error("Incorrect event type: #{incoming_notification}")
46
53
  end
47
54
  end
48
55
 
49
- def process_event_occupancy(publishers)
50
- @config.logger.debug("Occupancy process event with #{publishers} publishers") if @config.debug_enabled
51
- if publishers <= 0 && @publisher_available.value
56
+ def process_event_occupancy(channel, publishers)
57
+ @config.logger.debug("Processed occupancy event with #{publishers} publishers. Channel: #{channel}")
58
+
59
+ update_publishers(channel, publishers)
60
+
61
+ if !are_publishers_available? && @publisher_available.value
52
62
  @publisher_available.make_false
53
- dispatch_occupancy_event(false)
54
- elsif publishers >= 1 && !@publisher_available.value
63
+ dispatch_action(Constants::PUSH_SUBSYSTEM_DOWN)
64
+ elsif are_publishers_available? && !@publisher_available.value
55
65
  @publisher_available.make_true
56
- dispatch_occupancy_event(true)
66
+ dispatch_action(Constants::PUSH_SUBSYSTEM_READY)
67
+ end
68
+ end
69
+
70
+ def update_publishers(channel, publishers)
71
+ if channel == Constants::CONTROL_PRI
72
+ @telemetry_runtime_producer.record_streaming_event(Telemetry::Domain::Constants::OCCUPANCY_PRI, publishers)
73
+ @publishers_pri.value = publishers
74
+ elsif channel == Constants::CONTROL_SEC
75
+ @telemetry_runtime_producer.record_streaming_event(Telemetry::Domain::Constants::OCCUPANCY_SEC, publishers)
76
+ @publishers_sec.value = publishers
57
77
  end
58
78
  end
59
79
 
60
- def dispatch_occupancy_event(push_enable)
61
- @config.logger.debug("Dispatching occupancy event with publisher avaliable: #{push_enable}")
62
- @on[:occupancy].call(push_enable)
80
+ def are_publishers_available?
81
+ @publishers_pri.value.positive? || @publishers_sec.value.positive?
63
82
  end
64
83
 
65
- def dispatch_push_shutdown
66
- @config.logger.debug('Dispatching push shutdown')
67
- @on[:push_shutdown].call
84
+ def dispatch_action(action)
85
+ @config.logger.debug("Dispatching action: #{action}")
86
+ @on[:action].call(action)
68
87
  end
69
88
  end
70
89
  end