splitclient-rb 7.2.0.pre.rc1-java → 7.2.3-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5764d0cc133ca646667feff52d835db4e3904212
4
- data.tar.gz: 9639b14c964fd32db9b956243310ff52407c1897
3
+ metadata.gz: 5cacf8fc2c5e7cc181a03ef93f0757d203a8c135
4
+ data.tar.gz: 2087e7e94e486a11d6aef70dc2ba9866065ccef7
5
5
  SHA512:
6
- metadata.gz: 65cc44b9910152d1b921ed528d6c6a3791e9b084382222713ff58caa54d4bb643a768bf9a4d986a991670e9e836f9bc74c38732d2884fee501003e1fa8832f99
7
- data.tar.gz: da292d84762016a2a2b3277ff7d5001af863e8dc85f5826b22d8abb45a6de25df94c09355a7fea47e35a60b4398f355d2c0d42104464980e9b6d74283011b1e8
6
+ metadata.gz: aea9a06f4742233f7517068ed81bf31eebf462cf2095a9faa5baa8b12134ea4f2c83e37253b698d0cb943c4461c12a85eccce14f5db4f1ea0005fbe49ecaa468
7
+ data.tar.gz: 3831f2c06cdb55b2f7551501f5ffe7d01f511c9f97fe13d0a635e50ff5e7365118a47fd24780b6626731766ecaed0a901c5e590a79a0f02c4fa946e3bfb2bf22
data/.rubocop.yml CHANGED
@@ -10,6 +10,9 @@ Metrics/MethodLength:
10
10
  Metrics/ClassLength:
11
11
  Max: 150
12
12
 
13
+ Metrics/CyclomaticComplexity:
14
+ Max: 8
15
+
13
16
  Metrics/LineLength:
14
17
  Max: 130
15
18
  Exclude:
data/CHANGES.txt CHANGED
@@ -1,5 +1,18 @@
1
1
  CHANGES
2
2
 
3
+ 7.2.3 (Feb 24, 2021)
4
+ - Fixed missing segment fetch after an SPLIT_UPDATE.
5
+ - Updated streaming logic to support multiregion.
6
+ - Updated sse client connection logic to read confirmation event.
7
+ - Updated naming of retryable erros.
8
+
9
+ 7.2.2 (Dec 18, 2020)
10
+ - Fixed issue: undefined local variable or method post_impressions_count
11
+
12
+ 7.2.1 (Oct 23, 2020)
13
+ - Updated redis dependency to >= 4.2.2.
14
+ - Updated ably error handling.
15
+
3
16
  7.2.0 (Sep 25, 2020)
4
17
  - Added deduplication logic for impressions data.
5
18
  - Now there are two modes for Impressions when the SDK is in standalone mode, OPTIMIZED (default) that only ships unique impressions and DEBUG for times where you need to send ALL impressions to debug an integration.
@@ -27,14 +27,22 @@ module SplitIoClient
27
27
  end
28
28
  end
29
29
 
30
+ def fetch_segments_if_not_exists(names)
31
+ names.each do |name|
32
+ change_number = @segments_repository.get_change_number(name)
33
+
34
+ fetch_segment(name) if change_number == -1
35
+ end
36
+ rescue StandardError => error
37
+ @config.log_found_exception(__method__.to_s, error)
38
+ end
39
+
30
40
  def fetch_segment(name)
31
41
  @semaphore.synchronize do
32
42
  segments_api.fetch_segments_by_names([name])
33
- true
34
43
  end
35
44
  rescue StandardError => error
36
45
  @config.log_found_exception(__method__.to_s, error)
37
- false
38
46
  end
39
47
 
40
48
  def fetch_segments
@@ -41,11 +41,11 @@ module SplitIoClient
41
41
  @config.logger.debug("segments seen(#{data[:segment_names].length}): #{data[:segment_names].to_a}") if @config.debug_enabled
42
42
 
43
43
  @sdk_blocker.splits_ready!
44
- true
44
+
45
+ data[:segment_names]
45
46
  end
46
47
  rescue StandardError => error
47
48
  @config.log_found_exception(__method__.to_s, error)
48
- false
49
49
  end
50
50
 
51
51
  def stop_splits_thread
@@ -40,32 +40,32 @@ module SplitIoClient
40
40
  @config.logger.info('Posting impressions count due to shutdown')
41
41
  end
42
42
  end
43
+ end
43
44
 
44
- def post_impressions_count
45
- @impressions_api.post_count(formatter(@impression_counter.pop_all))
46
- rescue StandardError => error
47
- @config.log_found_exception(__method__.to_s, error)
48
- end
49
-
50
- def formatter(counts)
51
- return if counts.empty?
45
+ def post_impressions_count
46
+ @impressions_api.post_count(formatter(@impression_counter.pop_all))
47
+ rescue StandardError => error
48
+ @config.log_found_exception(__method__.to_s, error)
49
+ end
52
50
 
53
- formated_counts = {pf: []}
51
+ def formatter(counts)
52
+ return if counts.empty?
54
53
 
55
- counts.each do |key, value|
56
- key_splited = key.split('::')
57
-
58
- formated_counts[:pf] << {
59
- f: key_splited[0].to_s, # feature name
60
- m: key_splited[1].to_i, # time frame
61
- rc: value # count
62
- }
63
- end
54
+ formated_counts = {pf: []}
64
55
 
65
- formated_counts
66
- rescue StandardError => error
67
- @config.log_found_exception(__method__.to_s, error)
56
+ counts.each do |key, value|
57
+ key_splited = key.split('::')
58
+
59
+ formated_counts[:pf] << {
60
+ f: key_splited[0].to_s, # feature name
61
+ m: key_splited[1].to_i, # time frame
62
+ rc: value # count
63
+ }
68
64
  end
65
+
66
+ formated_counts
67
+ rescue StandardError => error
68
+ @config.log_found_exception(__method__.to_s, error)
69
69
  end
70
70
  end
71
71
  end
@@ -6,5 +6,10 @@ class SplitIoClient::Constants
6
6
  CONTROL_SEC = 'control_sec'
7
7
  OCCUPANCY_CHANNEL_PREFIX = '[?occupancy=metrics.publishers]'
8
8
  FETCH_BACK_OFF_BASE_RETRIES = 1
9
+ PUSH_CONNECTED = 'PUSH_CONNECTED'
10
+ PUSH_RETRYABLE_ERROR = 'PUSH_RETRYABLE_ERROR'
11
+ PUSH_NONRETRYABLE_ERROR = 'PUSH_NONRETRYABLE_ERROR'
12
+ PUSH_SUBSYSTEM_DOWN = 'PUSH_SUBSYSTEM_DOWN'
13
+ PUSH_SUBSYSTEM_READY = 'PUSH_SUBSYSTEM_READY'
14
+ PUSH_SUBSYSTEM_OFF = 'PUSH_SUBSYSTEM_OFF'
9
15
  end
10
-
@@ -19,12 +19,13 @@ module SplitIoClient
19
19
  if response[:push_enabled] && @sse_handler.start(response[:token], response[:channels])
20
20
  schedule_next_token_refresh(response[:exp])
21
21
  @back_off.reset
22
- return
22
+ return true
23
23
  end
24
24
 
25
25
  stop_sse
26
26
 
27
27
  schedule_next_token_refresh(@back_off.interval) if response[:retry]
28
+ false
28
29
  rescue StandardError => e
29
30
  @config.logger.error("start_sse: #{e.inspect}")
30
31
  end
@@ -11,8 +11,7 @@ module SplitIoClient
11
11
  )
12
12
  @synchronizer = synchronizer
13
13
  notification_manager_keeper = SplitIoClient::SSE::NotificationManagerKeeper.new(config) do |manager|
14
- manager.on_occupancy { |publisher_available| process_occupancy(publisher_available) }
15
- manager.on_push_shutdown { process_push_shutdown }
14
+ manager.on_action { |action| process_action(action) }
16
15
  end
17
16
  @sse_handler = SplitIoClient::SSE::SSEHandler.new(
18
17
  config,
@@ -21,8 +20,7 @@ module SplitIoClient
21
20
  repositories[:segments],
22
21
  notification_manager_keeper
23
22
  ) do |handler|
24
- handler.on_connected { process_connected }
25
- handler.on_disconnect { |reconnect| process_disconnect(reconnect) }
23
+ handler.on_action { |action| process_action(action) }
26
24
  end
27
25
 
28
26
  @push_manager = PushManager.new(config, @sse_handler, api_key)
@@ -44,10 +42,10 @@ module SplitIoClient
44
42
  # Starts tasks if stream is enabled.
45
43
  def start_stream
46
44
  @config.logger.debug('Starting push mode ...')
47
- stream_start_thread
45
+ sync_all_thread
48
46
  @synchronizer.start_periodic_data_recording
49
47
 
50
- stream_start_sse_thread
48
+ start_sse_connection_thread
51
49
  end
52
50
 
53
51
  def start_poll
@@ -59,23 +57,24 @@ module SplitIoClient
59
57
  end
60
58
 
61
59
  # Starts thread which fetch splits and segments once and trigger task to periodic data recording.
62
- def stream_start_thread
60
+ def sync_all_thread
63
61
  @config.threads[:sync_manager_start_stream] = Thread.new do
64
62
  begin
65
63
  @synchronizer.sync_all
66
64
  rescue StandardError => e
67
- @config.logger.error("stream_start_thread error : #{e.inspect}")
65
+ @config.logger.error("sync_all_thread error : #{e.inspect}")
68
66
  end
69
67
  end
70
68
  end
71
69
 
72
70
  # Starts thread which connect to sse and after that fetch splits and segments once.
73
- def stream_start_sse_thread
71
+ def start_sse_connection_thread
74
72
  @config.threads[:sync_manager_start_sse] = Thread.new do
75
73
  begin
76
- @push_manager.start_sse
74
+ connected = @push_manager.start_sse
75
+ @synchronizer.start_periodic_fetch unless connected
77
76
  rescue StandardError => e
78
- @config.logger.error("stream_start_sse_thread error : #{e.inspect}")
77
+ @config.logger.error("start_sse_connection_thread error : #{e.inspect}")
79
78
  end
80
79
  end
81
80
  end
@@ -84,6 +83,46 @@ module SplitIoClient
84
83
  PhusionPassenger.on_event(:starting_worker_process) { |forked| start_stream if forked }
85
84
  end
86
85
 
86
+ def process_action(action)
87
+ case action
88
+ when Constants::PUSH_CONNECTED
89
+ process_connected
90
+ when Constants::PUSH_RETRYABLE_ERROR
91
+ process_disconnect(true)
92
+ when Constants::PUSH_NONRETRYABLE_ERROR
93
+ process_disconnect(false)
94
+ when Constants::PUSH_SUBSYSTEM_DOWN
95
+ process_subsystem_down
96
+ when Constants::PUSH_SUBSYSTEM_READY
97
+ process_subsystem_ready
98
+ when Constants::PUSH_SUBSYSTEM_OFF
99
+ process_push_shutdown
100
+ else
101
+ @config.logger.debug('Incorrect action type.')
102
+ end
103
+ rescue StandardError => e
104
+ @config.logger.error("process_action error: #{e.inspect}")
105
+ end
106
+
107
+ def process_subsystem_ready
108
+ @synchronizer.stop_periodic_fetch
109
+ @synchronizer.sync_all
110
+ @sse_handler.start_workers
111
+ end
112
+
113
+ def process_subsystem_down
114
+ @sse_handler.stop_workers
115
+ @synchronizer.start_periodic_fetch
116
+ end
117
+
118
+ def process_push_shutdown
119
+ @push_manager.stop_sse
120
+ @sse_handler.stop_workers
121
+ @synchronizer.start_periodic_fetch
122
+ rescue StandardError => e
123
+ @config.logger.error("process_push_shutdown error: #{e.inspect}")
124
+ end
125
+
87
126
  def process_connected
88
127
  if @sse_connected.value
89
128
  @config.logger.debug('Streaming already connected.')
@@ -115,28 +154,6 @@ module SplitIoClient
115
154
  rescue StandardError => e
116
155
  @config.logger.error("process_disconnect error: #{e.inspect}")
117
156
  end
118
-
119
- def process_occupancy(push_enable)
120
- if push_enable
121
- @synchronizer.stop_periodic_fetch
122
- @synchronizer.sync_all
123
- @sse_handler.start_workers
124
- return
125
- end
126
-
127
- @sse_handler.stop_workers
128
- @synchronizer.start_periodic_fetch
129
- rescue StandardError => e
130
- @config.logger.error("process_occupancy error: #{e.inspect}")
131
- end
132
-
133
- def process_push_shutdown
134
- @push_manager.stop_sse
135
- @sse_handler.stop_workers
136
- @synchronizer.start_periodic_fetch
137
- rescue StandardError => e
138
- @config.logger.error("process_push_shutdown error: #{e.inspect}")
139
- end
140
157
  end
141
158
  end
142
159
  end
@@ -30,7 +30,7 @@ module SplitIoClient
30
30
  def sync_all
31
31
  @config.threads[:sync_all_thread] = Thread.new do
32
32
  @config.logger.debug('Synchronizing Splits and Segments ...') if @config.debug_enabled
33
- fetch_splits
33
+ @split_fetcher.fetch_splits
34
34
  fetch_segments
35
35
  end
36
36
  end
@@ -53,21 +53,12 @@ module SplitIoClient
53
53
  end
54
54
 
55
55
  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
56
+ segment_names = @split_fetcher.fetch_splits
57
+ @segment_fetcher.fetch_segments_if_not_exists(segment_names) unless segment_names.empty?
62
58
  end
63
59
 
64
60
  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
61
+ @segment_fetcher.fetch_segment(name)
71
62
  end
72
63
 
73
64
  private
@@ -9,6 +9,7 @@ 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
 
@@ -16,9 +17,10 @@ module SplitIoClient
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: ->(_) {} }
22
24
 
23
25
  yield self if block_given?
24
26
  end
@@ -27,16 +29,12 @@ module SplitIoClient
27
29
  @on[:event] = action
28
30
  end
29
31
 
30
- def on_connected(&action)
31
- @on[:connected] = action
32
+ def on_action(&action)
33
+ @on[:action] = action
32
34
  end
33
35
 
34
- def on_disconnect(&action)
35
- @on[:disconnect] = action
36
- end
37
-
38
- def close(reconnect = false)
39
- dispatch_disconnect(reconnect)
36
+ def close(action = Constants::PUSH_NONRETRYABLE_ERROR)
37
+ dispatch_action(action)
40
38
  @connected.make_false
41
39
  SplitIoClient::Helpers::ThreadHelper.stop(:connect_stream, @config)
42
40
  @socket&.close
@@ -45,6 +43,11 @@ module SplitIoClient
45
43
  end
46
44
 
47
45
  def start(url)
46
+ if connected?
47
+ @config.logger.debug('SSEClient already running.')
48
+ return true
49
+ end
50
+
48
51
  @uri = URI(url)
49
52
  latch = Concurrent::CountDownLatch.new(1)
50
53
 
@@ -72,16 +75,18 @@ module SplitIoClient
72
75
  end
73
76
 
74
77
  def connect_stream(latch)
75
- socket_write(latch)
78
+ socket_write
76
79
 
77
- while @connected.value
80
+ while connected? || @first_event.value
78
81
  begin
79
82
  partial_data = @socket.readpartial(10_000, timeout: @read_timeout)
80
83
 
84
+ read_first_event(partial_data, latch)
85
+
81
86
  raise 'eof exception' if partial_data == :eof
82
87
  rescue StandardError => e
83
88
  @config.logger.error('Error reading partial data: ' + e.inspect) if @config.debug_enabled
84
- close(true) # close conexion & reconnect
89
+ close(Constants::PUSH_RETRYABLE_ERROR)
85
90
  return
86
91
  end
87
92
 
@@ -89,14 +94,31 @@ module SplitIoClient
89
94
  end
90
95
  end
91
96
 
92
- def socket_write(latch)
97
+ def socket_write
98
+ @first_event.make_true
93
99
  @socket = socket_connect
94
100
  @socket.write(build_request(@uri))
95
- dispatch_connected
96
101
  rescue StandardError => e
97
102
  @config.logger.error("Error during connecting to #{@uri.host}. Error: #{e.inspect}")
98
- close
99
- ensure
103
+ close(Constants::PUSH_NONRETRYABLE_ERROR)
104
+ end
105
+
106
+ def read_first_event(data, latch)
107
+ return unless @first_event.value
108
+
109
+ response_code = @event_parser.first_event(data)
110
+ @config.logger.debug("SSE client first event code: #{response_code}")
111
+
112
+ error_event = false
113
+ events = @event_parser.parse(data)
114
+ events.each { |e| error_event = true if e.event_type == ERROR_EVENT_TYPE }
115
+ @first_event.make_false
116
+
117
+ if response_code == OK_CODE && !error_event
118
+ @connected.make_true
119
+ dispatch_action(Constants::PUSH_CONNECTED)
120
+ end
121
+
100
122
  latch.count_down
101
123
  end
102
124
 
@@ -137,9 +159,9 @@ module SplitIoClient
137
159
  def dispatch_error(event)
138
160
  @config.logger.error("Event error: #{event.event_type}, #{event.data}")
139
161
  if event.data['code'] >= 40_140 && event.data['code'] <= 40_149
140
- close(true) # close conexion & reconnect
162
+ close(Constants::PUSH_RETRYABLE_ERROR)
141
163
  elsif event.data['code'] >= 40_000 && event.data['code'] <= 49_999
142
- close # close conexion
164
+ close(Constants::PUSH_NONRETRYABLE_ERROR)
143
165
  end
144
166
  end
145
167
 
@@ -148,15 +170,9 @@ module SplitIoClient
148
170
  @on[:event].call(event)
149
171
  end
150
172
 
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)
173
+ def dispatch_action(action)
174
+ @config.logger.debug("Dispatching action: #{action}") if @config.debug_enabled
175
+ @on[:action].call(action)
160
176
  end
161
177
  end
162
178
  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,6 +1,6 @@
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
@@ -8,7 +8,9 @@ module SplitIoClient
8
8
  def initialize(config)
9
9
  @config = config
10
10
  @publisher_available = Concurrent::AtomicBoolean.new(true)
11
- @on = { occupancy: ->(_) {}, push_shutdown: ->(_) {} }
11
+ @publishers_pri = Concurrent::AtomicFixnum.new
12
+ @publishers_sec = Concurrent::AtomicFixnum.new
13
+ @on = { action: ->(_) {} }
12
14
 
13
15
  yield self if block_given?
14
16
  end
@@ -16,19 +18,15 @@ module SplitIoClient
16
18
  def handle_incoming_occupancy_event(event)
17
19
  if event.data['type'] == 'CONTROL'
18
20
  process_event_control(event.data['controlType'])
19
- elsif event.channel == SplitIoClient::Constants::CONTROL_PRI
20
- process_event_occupancy(event.data['metrics']['publishers'])
21
+ else
22
+ process_event_occupancy(event.channel, event.data['metrics']['publishers'])
21
23
  end
22
24
  rescue StandardError => e
23
25
  @config.logger.error(e)
24
26
  end
25
27
 
26
- def on_occupancy(&action)
27
- @on[:occupancy] = action
28
- end
29
-
30
- def on_push_shutdown(&action)
31
- @on[:push_shutdown] = action
28
+ def on_action(&action)
29
+ @on[:action] = action
32
30
  end
33
31
 
34
32
  private
@@ -36,35 +34,42 @@ module SplitIoClient
36
34
  def process_event_control(type)
37
35
  case type
38
36
  when 'STREAMING_PAUSED'
39
- dispatch_occupancy_event(false)
37
+ dispatch_action(Constants::PUSH_SUBSYSTEM_DOWN)
40
38
  when 'STREAMING_RESUMED'
41
- dispatch_occupancy_event(true) if @publisher_available.value
39
+ dispatch_action(Constants::PUSH_SUBSYSTEM_READY) if @publisher_available.value
42
40
  when 'STREAMING_DISABLED'
43
- dispatch_push_shutdown
41
+ dispatch_action(Constants::PUSH_SUBSYSTEM_OFF)
44
42
  else
45
43
  @config.logger.error("Incorrect event type: #{incoming_notification}")
46
44
  end
47
45
  end
48
46
 
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
47
+ def process_event_occupancy(channel, publishers)
48
+ @config.logger.debug("Processed occupancy event with #{publishers} publishers. Channel: #{channel}")
49
+
50
+ update_publishers(channel, publishers)
51
+
52
+ if !are_publishers_available? && @publisher_available.value
52
53
  @publisher_available.make_false
53
- dispatch_occupancy_event(false)
54
- elsif publishers >= 1 && !@publisher_available.value
54
+ dispatch_action(Constants::PUSH_SUBSYSTEM_DOWN)
55
+ elsif are_publishers_available? && !@publisher_available.value
55
56
  @publisher_available.make_true
56
- dispatch_occupancy_event(true)
57
+ dispatch_action(Constants::PUSH_SUBSYSTEM_READY)
57
58
  end
58
59
  end
59
60
 
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)
61
+ def update_publishers(channel, publishers)
62
+ @publishers_pri.value = publishers if channel == Constants::CONTROL_PRI
63
+ @publishers_sec.value = publishers if channel == Constants::CONTROL_SEC
64
+ end
65
+
66
+ def are_publishers_available?
67
+ @publishers_pri.value.positive? || @publishers_sec.value.positive?
63
68
  end
64
69
 
65
- def dispatch_push_shutdown
66
- @config.logger.debug('Dispatching push shutdown')
67
- @on[:push_shutdown].call
70
+ def dispatch_action(action)
71
+ @config.logger.debug("Dispatching action: #{action}")
72
+ @on[:action].call(action)
68
73
  end
69
74
  end
70
75
  end
@@ -13,11 +13,10 @@ module SplitIoClient
13
13
  @notification_processor = SplitIoClient::SSE::NotificationProcessor.new(config, @splits_worker, @segments_worker)
14
14
  @sse_client = SSE::EventSource::Client.new(@config) do |client|
15
15
  client.on_event { |event| handle_incoming_message(event) }
16
- client.on_connected { process_connected }
17
- client.on_disconnect { |reconnect| process_disconnect(reconnect) }
16
+ client.on_action { |action| process_action(action) }
18
17
  end
19
18
 
20
- @on = { connected: ->(_) {}, disconnect: ->(_) {} }
19
+ @on = { action: ->(_) {} }
21
20
 
22
21
  yield self if block_given?
23
22
  end
@@ -48,22 +47,14 @@ module SplitIoClient
48
47
  @segments_worker.stop
49
48
  end
50
49
 
51
- def on_connected(&action)
52
- @on[:connected] = action
53
- end
54
-
55
- def on_disconnect(&action)
56
- @on[:disconnect] = action
57
- end
58
-
59
- def process_disconnect(reconnect)
60
- @on[:disconnect].call(reconnect)
50
+ def on_action(&action)
51
+ @on[:action] = action
61
52
  end
62
53
 
63
54
  private
64
55
 
65
- def process_connected
66
- @on[:connected].call
56
+ def process_action(action)
57
+ @on[:action].call(action)
67
58
  end
68
59
 
69
60
  def handle_incoming_message(notification)
@@ -48,12 +48,13 @@ module SplitIoClient
48
48
  def perform
49
49
  while (item = @queue.pop)
50
50
  segment_name = item[:segment_name]
51
- change_number = item[:change_number]
52
- since = @segments_repository.get_change_number(segment_name)
51
+ cn = item[:change_number]
52
+ @config.logger.debug("SegmentsWorker change_number dequeue #{segment_name}, #{cn}")
53
53
 
54
- unless since >= change_number
55
- @config.logger.debug("SegmentsWorker fetch_segment with #{since}")
54
+ attempt = 0
55
+ while cn > @segments_repository.get_change_number(segment_name).to_i && attempt <= Workers::MAX_RETRIES_ALLOWED
56
56
  @synchronizer.fetch_segment(segment_name)
57
+ attempt += 1
57
58
  end
58
59
  end
59
60
  end
@@ -3,6 +3,8 @@
3
3
  module SplitIoClient
4
4
  module SSE
5
5
  module Workers
6
+ MAX_RETRIES_ALLOWED = 10
7
+
6
8
  class SplitsWorker
7
9
  def initialize(synchronizer, config, splits_repository)
8
10
  @synchronizer = synchronizer
@@ -59,11 +61,12 @@ module SplitIoClient
59
61
 
60
62
  def perform
61
63
  while (change_number = @queue.pop)
62
- since = @splits_repository.get_change_number
64
+ @config.logger.debug("SplitsWorker change_number dequeue #{change_number}")
63
65
 
64
- unless since.to_i >= change_number
65
- @config.logger.debug("SplitsWorker fetch_splits with #{since}")
66
+ attempt = 0
67
+ while change_number > @splits_repository.get_change_number.to_i && attempt <= Workers::MAX_RETRIES_ALLOWED
66
68
  @synchronizer.fetch_splits
69
+ attempt += 1
67
70
  end
68
71
  end
69
72
  end
@@ -1,3 +1,3 @@
1
1
  module SplitIoClient
2
- VERSION = '7.2.0.pre.rc1'
2
+ VERSION = '7.2.3'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: splitclient-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.0.pre.rc1
4
+ version: 7.2.3
5
5
  platform: java
6
6
  authors:
7
7
  - Split Software
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-19 00:00:00.000000000 Z
11
+ date: 2021-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -450,9 +450,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
450
450
  version: '0'
451
451
  required_rubygems_version: !ruby/object:Gem::Requirement
452
452
  requirements:
453
- - - ">"
453
+ - - ">="
454
454
  - !ruby/object:Gem::Version
455
- version: 1.3.1
455
+ version: '0'
456
456
  requirements: []
457
457
  rubyforge_project:
458
458
  rubygems_version: 2.6.14