optimizely-sdk 5.0.0 → 5.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +202 -202
  3. data/lib/optimizely/audience.rb +127 -127
  4. data/lib/optimizely/bucketer.rb +156 -156
  5. data/lib/optimizely/condition_tree_evaluator.rb +123 -123
  6. data/lib/optimizely/config/datafile_project_config.rb +558 -558
  7. data/lib/optimizely/config/proxy_config.rb +34 -34
  8. data/lib/optimizely/config_manager/async_scheduler.rb +95 -95
  9. data/lib/optimizely/config_manager/http_project_config_manager.rb +340 -340
  10. data/lib/optimizely/config_manager/project_config_manager.rb +25 -25
  11. data/lib/optimizely/config_manager/static_project_config_manager.rb +55 -55
  12. data/lib/optimizely/decide/optimizely_decide_option.rb +28 -28
  13. data/lib/optimizely/decide/optimizely_decision.rb +60 -60
  14. data/lib/optimizely/decide/optimizely_decision_message.rb +26 -26
  15. data/lib/optimizely/decision_service.rb +563 -563
  16. data/lib/optimizely/error_handler.rb +39 -39
  17. data/lib/optimizely/event/batch_event_processor.rb +235 -235
  18. data/lib/optimizely/event/entity/conversion_event.rb +44 -44
  19. data/lib/optimizely/event/entity/decision.rb +38 -38
  20. data/lib/optimizely/event/entity/event_batch.rb +86 -86
  21. data/lib/optimizely/event/entity/event_context.rb +50 -50
  22. data/lib/optimizely/event/entity/impression_event.rb +48 -48
  23. data/lib/optimizely/event/entity/snapshot.rb +33 -33
  24. data/lib/optimizely/event/entity/snapshot_event.rb +48 -48
  25. data/lib/optimizely/event/entity/user_event.rb +22 -22
  26. data/lib/optimizely/event/entity/visitor.rb +36 -36
  27. data/lib/optimizely/event/entity/visitor_attribute.rb +38 -38
  28. data/lib/optimizely/event/event_factory.rb +156 -156
  29. data/lib/optimizely/event/event_processor.rb +25 -25
  30. data/lib/optimizely/event/forwarding_event_processor.rb +44 -44
  31. data/lib/optimizely/event/user_event_factory.rb +88 -88
  32. data/lib/optimizely/event_builder.rb +221 -221
  33. data/lib/optimizely/event_dispatcher.rb +69 -69
  34. data/lib/optimizely/exceptions.rb +193 -193
  35. data/lib/optimizely/helpers/constants.rb +459 -459
  36. data/lib/optimizely/helpers/date_time_utils.rb +30 -30
  37. data/lib/optimizely/helpers/event_tag_utils.rb +132 -132
  38. data/lib/optimizely/helpers/group.rb +31 -31
  39. data/lib/optimizely/helpers/http_utils.rb +68 -68
  40. data/lib/optimizely/helpers/sdk_settings.rb +61 -61
  41. data/lib/optimizely/helpers/validator.rb +236 -236
  42. data/lib/optimizely/helpers/variable_type.rb +67 -67
  43. data/lib/optimizely/logger.rb +46 -46
  44. data/lib/optimizely/notification_center.rb +174 -174
  45. data/lib/optimizely/notification_center_registry.rb +71 -71
  46. data/lib/optimizely/odp/lru_cache.rb +114 -114
  47. data/lib/optimizely/odp/odp_config.rb +102 -102
  48. data/lib/optimizely/odp/odp_event.rb +75 -75
  49. data/lib/optimizely/odp/odp_event_api_manager.rb +70 -70
  50. data/lib/optimizely/odp/odp_event_manager.rb +286 -286
  51. data/lib/optimizely/odp/odp_manager.rb +159 -159
  52. data/lib/optimizely/odp/odp_segment_api_manager.rb +122 -122
  53. data/lib/optimizely/odp/odp_segment_manager.rb +97 -97
  54. data/lib/optimizely/optimizely_config.rb +273 -273
  55. data/lib/optimizely/optimizely_factory.rb +184 -184
  56. data/lib/optimizely/optimizely_user_context.rb +238 -238
  57. data/lib/optimizely/params.rb +31 -31
  58. data/lib/optimizely/project_config.rb +99 -99
  59. data/lib/optimizely/semantic_version.rb +166 -166
  60. data/lib/optimizely/user_condition_evaluator.rb +391 -391
  61. data/lib/optimizely/user_profile_service.rb +35 -35
  62. data/lib/optimizely/version.rb +21 -21
  63. data/lib/optimizely.rb +1262 -1262
  64. metadata +7 -5
@@ -1,286 +1,286 @@
1
- # frozen_string_literal: true
2
-
3
- #
4
- # Copyright 2019, 2022, Optimizely and contributors
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
- require_relative 'odp_event_api_manager'
19
- require_relative '../helpers/constants'
20
- require_relative 'odp_event'
21
-
22
- module Optimizely
23
- class OdpEventManager
24
- # Events passed to the OdpEventManager are immediately added to an EventQueue.
25
- # The OdpEventManager maintains a single consumer thread that pulls events off of
26
- # the BlockingQueue and buffers them for either a configured batch size or for a
27
- # maximum duration before the resulting OdpEvent is sent to Odp.
28
-
29
- attr_reader :batch_size, :api_manager, :logger
30
- attr_accessor :odp_config
31
-
32
- def initialize(
33
- api_manager: nil,
34
- logger: NoOpLogger.new,
35
- proxy_config: nil,
36
- request_timeout: nil,
37
- flush_interval: nil
38
- )
39
- @odp_config = nil
40
- @api_host = nil
41
- @api_key = nil
42
-
43
- @mutex = Mutex.new
44
- @event_queue = SizedQueue.new(Optimizely::Helpers::Constants::ODP_EVENT_MANAGER[:DEFAULT_QUEUE_CAPACITY])
45
- @queue_capacity = Helpers::Constants::ODP_EVENT_MANAGER[:DEFAULT_QUEUE_CAPACITY]
46
- # received signal should be sent after adding item to event_queue
47
- @received = ConditionVariable.new
48
- @logger = logger
49
- @api_manager = api_manager || OdpEventApiManager.new(logger: @logger, proxy_config: proxy_config, timeout: request_timeout)
50
- @flush_interval = flush_interval || Helpers::Constants::ODP_EVENT_MANAGER[:DEFAULT_FLUSH_INTERVAL_SECONDS]
51
- @batch_size = @flush_interval&.zero? ? 1 : Helpers::Constants::ODP_EVENT_MANAGER[:DEFAULT_BATCH_SIZE]
52
- @flush_deadline = 0
53
- @retry_count = Helpers::Constants::ODP_EVENT_MANAGER[:DEFAULT_RETRY_COUNT]
54
- # current_batch should only be accessed by processing thread
55
- @current_batch = []
56
- @thread = nil
57
- @thread_exception = false
58
- end
59
-
60
- def start!(odp_config)
61
- if running?
62
- @logger.log(Logger::WARN, 'Service already started.')
63
- return
64
- end
65
-
66
- @odp_config = odp_config
67
- @api_host = odp_config.api_host
68
- @api_key = odp_config.api_key
69
-
70
- @thread = Thread.new { run }
71
- @logger.log(Logger::INFO, 'Starting scheduler.')
72
- end
73
-
74
- def flush
75
- begin
76
- @event_queue.push(:FLUSH_SIGNAL, true)
77
- rescue ThreadError
78
- @logger.log(Logger::ERROR, 'Error flushing ODP event queue.')
79
- return
80
- end
81
-
82
- @mutex.synchronize do
83
- @received.signal
84
- end
85
- end
86
-
87
- def update_config
88
- begin
89
- # Adds update config signal to event_queue.
90
- @event_queue.push(:UPDATE_CONFIG, true)
91
- rescue ThreadError
92
- @logger.log(Logger::ERROR, 'Error updating ODP config for the event queue')
93
- end
94
-
95
- @mutex.synchronize do
96
- @received.signal
97
- end
98
- end
99
-
100
- def dispatch(event)
101
- if @thread_exception
102
- @logger.log(Logger::ERROR, format(Helpers::Constants::ODP_LOGS[:ODP_EVENT_FAILED], 'Queue is down'))
103
- return
104
- end
105
-
106
- # if the processor has been explicitly stopped. Don't accept tasks
107
- unless running?
108
- @logger.log(Logger::WARN, 'ODP event queue is shutdown, not accepting events.')
109
- return
110
- end
111
-
112
- begin
113
- @logger.log(Logger::DEBUG, 'ODP event queue: adding event.')
114
- @event_queue.push(event, true)
115
- rescue => e
116
- @logger.log(Logger::WARN, format(Helpers::Constants::ODP_LOGS[:ODP_EVENT_FAILED], e.message))
117
- return
118
- end
119
-
120
- @mutex.synchronize do
121
- @received.signal
122
- end
123
- end
124
-
125
- def send_event(type:, action:, identifiers:, data:)
126
- case @odp_config&.odp_state
127
- when nil
128
- @logger.log(Logger::DEBUG, 'ODP event queue: cannot send before config has been set.')
129
- return
130
- when OdpConfig::ODP_CONFIG_STATE[:UNDETERMINED]
131
- @logger.log(Logger::DEBUG, 'ODP event queue: cannot send before the datafile has loaded.')
132
- return
133
- when OdpConfig::ODP_CONFIG_STATE[:NOT_INTEGRATED]
134
- @logger.log(Logger::DEBUG, Helpers::Constants::ODP_LOGS[:ODP_NOT_INTEGRATED])
135
- return
136
- end
137
-
138
- event = Optimizely::OdpEvent.new(type: type, action: action, identifiers: identifiers, data: data)
139
- dispatch(event)
140
- end
141
-
142
- def stop!
143
- return unless running?
144
-
145
- begin
146
- @event_queue.push(:SHUTDOWN_SIGNAL, true)
147
- rescue ThreadError
148
- @logger.log(Logger::ERROR, 'Error stopping ODP event queue.')
149
- return
150
- end
151
-
152
- @event_queue.close
153
-
154
- @mutex.synchronize do
155
- @received.signal
156
- end
157
-
158
- @logger.log(Logger::INFO, 'Stopping ODP event queue.')
159
-
160
- @thread.join
161
-
162
- @logger.log(Logger::ERROR, format(Helpers::Constants::ODP_LOGS[:ODP_EVENT_FAILED], @current_batch.to_json)) unless @current_batch.empty?
163
- end
164
-
165
- def running?
166
- !!@thread && !!@thread.status && !@event_queue.closed?
167
- end
168
-
169
- private
170
-
171
- def run
172
- loop do
173
- @mutex.synchronize do
174
- @received.wait(@mutex, queue_timeout) if @event_queue.empty?
175
- end
176
-
177
- begin
178
- item = @event_queue.pop(true)
179
- rescue ThreadError => e
180
- raise unless e.message == 'queue empty'
181
-
182
- item = nil
183
- end
184
-
185
- case item
186
- when :SHUTDOWN_SIGNAL
187
- @logger.log(Logger::DEBUG, 'ODP event queue: received shutdown signal.')
188
- break
189
-
190
- when :FLUSH_SIGNAL
191
- @logger.log(Logger::DEBUG, 'ODP event queue: received flush signal.')
192
- flush_batch!
193
-
194
- when :UPDATE_CONFIG
195
- @logger.log(Logger::DEBUG, 'ODP event queue: received update config signal.')
196
- process_config_update
197
-
198
- when Optimizely::OdpEvent
199
- add_to_batch(item)
200
-
201
- when nil && !@current_batch.empty?
202
- @logger.log(Logger::DEBUG, 'ODP event queue: flushing on interval.')
203
- flush_batch!
204
- end
205
- end
206
- rescue SignalException
207
- @thread_exception = true
208
- @logger.log(Logger::ERROR, 'Interrupted while processing ODP events.')
209
- rescue => e
210
- @thread_exception = true
211
- @logger.log(Logger::ERROR, "Uncaught exception processing ODP events. Error: #{e.message}")
212
- ensure
213
- @logger.log(Logger::INFO, 'Exiting ODP processing loop. Attempting to flush pending events.')
214
- flush_batch!
215
- end
216
-
217
- def flush_batch!
218
- if @current_batch.empty?
219
- @logger.log(Logger::DEBUG, 'ODP event queue: nothing to flush.')
220
- return
221
- end
222
-
223
- if @api_key.nil? || @api_host.nil?
224
- @logger.log(Logger::DEBUG, Helpers::Constants::ODP_LOGS[:ODP_NOT_INTEGRATED])
225
- @current_batch.clear
226
- return
227
- end
228
-
229
- @logger.log(Logger::DEBUG, "ODP event queue: flushing batch size #{@current_batch.length}.")
230
- should_retry = false
231
-
232
- i = 0
233
- while i < @retry_count
234
- begin
235
- should_retry = @api_manager.send_odp_events(@api_key, @api_host, @current_batch)
236
- rescue StandardError => e
237
- should_retry = false
238
- @logger.log(Logger::ERROR, format(Helpers::Constants::ODP_LOGS[:ODP_EVENT_FAILED], "Error: #{e.message} #{@current_batch.to_json}"))
239
- end
240
- break unless should_retry
241
-
242
- @logger.log(Logger::DEBUG, 'Error dispatching ODP events, scheduled to retry.') if i < @retry_count
243
- i += 1
244
- end
245
-
246
- @logger.log(Logger::ERROR, format(Helpers::Constants::ODP_LOGS[:ODP_EVENT_FAILED], "Failed after #{i} retries: #{@current_batch.to_json}")) if should_retry
247
-
248
- @current_batch.clear
249
- end
250
-
251
- def add_to_batch(event)
252
- set_flush_deadline if @current_batch.empty?
253
-
254
- @current_batch << event
255
- return unless @current_batch.length >= @batch_size
256
-
257
- @logger.log(Logger::DEBUG, 'ODP event queue: flushing on batch size.')
258
- flush_batch!
259
- end
260
-
261
- def set_flush_deadline
262
- # Sets time that next flush will occur.
263
- @flush_deadline = Time.new + @flush_interval
264
- end
265
-
266
- def time_till_flush
267
- # Returns seconds until next flush; no less than 0.
268
- [0, @flush_deadline - Time.new].max
269
- end
270
-
271
- def queue_timeout
272
- # Returns seconds until next flush or None if current batch is empty.
273
- return nil if @current_batch.empty?
274
-
275
- time_till_flush
276
- end
277
-
278
- def process_config_update
279
- # Updates the configuration used to send events.
280
- flush_batch! unless @current_batch.empty?
281
-
282
- @api_key = @odp_config&.api_key
283
- @api_host = @odp_config&.api_host
284
- end
285
- end
286
- end
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright 2019, 2022, Optimizely and contributors
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ require_relative 'odp_event_api_manager'
19
+ require_relative '../helpers/constants'
20
+ require_relative 'odp_event'
21
+
22
+ module Optimizely
23
+ class OdpEventManager
24
+ # Events passed to the OdpEventManager are immediately added to an EventQueue.
25
+ # The OdpEventManager maintains a single consumer thread that pulls events off of
26
+ # the BlockingQueue and buffers them for either a configured batch size or for a
27
+ # maximum duration before the resulting OdpEvent is sent to Odp.
28
+
29
+ attr_reader :batch_size, :api_manager, :logger
30
+ attr_accessor :odp_config
31
+
32
+ def initialize(
33
+ api_manager: nil,
34
+ logger: NoOpLogger.new,
35
+ proxy_config: nil,
36
+ request_timeout: nil,
37
+ flush_interval: nil
38
+ )
39
+ @odp_config = nil
40
+ @api_host = nil
41
+ @api_key = nil
42
+
43
+ @mutex = Mutex.new
44
+ @event_queue = SizedQueue.new(Optimizely::Helpers::Constants::ODP_EVENT_MANAGER[:DEFAULT_QUEUE_CAPACITY])
45
+ @queue_capacity = Helpers::Constants::ODP_EVENT_MANAGER[:DEFAULT_QUEUE_CAPACITY]
46
+ # received signal should be sent after adding item to event_queue
47
+ @received = ConditionVariable.new
48
+ @logger = logger
49
+ @api_manager = api_manager || OdpEventApiManager.new(logger: @logger, proxy_config: proxy_config, timeout: request_timeout)
50
+ @flush_interval = flush_interval || Helpers::Constants::ODP_EVENT_MANAGER[:DEFAULT_FLUSH_INTERVAL_SECONDS]
51
+ @batch_size = @flush_interval&.zero? ? 1 : Helpers::Constants::ODP_EVENT_MANAGER[:DEFAULT_BATCH_SIZE]
52
+ @flush_deadline = 0
53
+ @retry_count = Helpers::Constants::ODP_EVENT_MANAGER[:DEFAULT_RETRY_COUNT]
54
+ # current_batch should only be accessed by processing thread
55
+ @current_batch = []
56
+ @thread = nil
57
+ @thread_exception = false
58
+ end
59
+
60
+ def start!(odp_config)
61
+ if running?
62
+ @logger.log(Logger::WARN, 'Service already started.')
63
+ return
64
+ end
65
+
66
+ @odp_config = odp_config
67
+ @api_host = odp_config.api_host
68
+ @api_key = odp_config.api_key
69
+
70
+ @thread = Thread.new { run }
71
+ @logger.log(Logger::INFO, 'Starting scheduler.')
72
+ end
73
+
74
+ def flush
75
+ begin
76
+ @event_queue.push(:FLUSH_SIGNAL, true)
77
+ rescue ThreadError
78
+ @logger.log(Logger::ERROR, 'Error flushing ODP event queue.')
79
+ return
80
+ end
81
+
82
+ @mutex.synchronize do
83
+ @received.signal
84
+ end
85
+ end
86
+
87
+ def update_config
88
+ begin
89
+ # Adds update config signal to event_queue.
90
+ @event_queue.push(:UPDATE_CONFIG, true)
91
+ rescue ThreadError
92
+ @logger.log(Logger::ERROR, 'Error updating ODP config for the event queue')
93
+ end
94
+
95
+ @mutex.synchronize do
96
+ @received.signal
97
+ end
98
+ end
99
+
100
+ def dispatch(event)
101
+ if @thread_exception
102
+ @logger.log(Logger::ERROR, format(Helpers::Constants::ODP_LOGS[:ODP_EVENT_FAILED], 'Queue is down'))
103
+ return
104
+ end
105
+
106
+ # if the processor has been explicitly stopped. Don't accept tasks
107
+ unless running?
108
+ @logger.log(Logger::WARN, 'ODP event queue is shutdown, not accepting events.')
109
+ return
110
+ end
111
+
112
+ begin
113
+ @logger.log(Logger::DEBUG, 'ODP event queue: adding event.')
114
+ @event_queue.push(event, true)
115
+ rescue => e
116
+ @logger.log(Logger::WARN, format(Helpers::Constants::ODP_LOGS[:ODP_EVENT_FAILED], e.message))
117
+ return
118
+ end
119
+
120
+ @mutex.synchronize do
121
+ @received.signal
122
+ end
123
+ end
124
+
125
+ def send_event(type:, action:, identifiers:, data:)
126
+ case @odp_config&.odp_state
127
+ when nil
128
+ @logger.log(Logger::DEBUG, 'ODP event queue: cannot send before config has been set.')
129
+ return
130
+ when OdpConfig::ODP_CONFIG_STATE[:UNDETERMINED]
131
+ @logger.log(Logger::DEBUG, 'ODP event queue: cannot send before the datafile has loaded.')
132
+ return
133
+ when OdpConfig::ODP_CONFIG_STATE[:NOT_INTEGRATED]
134
+ @logger.log(Logger::DEBUG, Helpers::Constants::ODP_LOGS[:ODP_NOT_INTEGRATED])
135
+ return
136
+ end
137
+
138
+ event = Optimizely::OdpEvent.new(type: type, action: action, identifiers: identifiers, data: data)
139
+ dispatch(event)
140
+ end
141
+
142
+ def stop!
143
+ return unless running?
144
+
145
+ begin
146
+ @event_queue.push(:SHUTDOWN_SIGNAL, true)
147
+ rescue ThreadError
148
+ @logger.log(Logger::ERROR, 'Error stopping ODP event queue.')
149
+ return
150
+ end
151
+
152
+ @event_queue.close
153
+
154
+ @mutex.synchronize do
155
+ @received.signal
156
+ end
157
+
158
+ @logger.log(Logger::INFO, 'Stopping ODP event queue.')
159
+
160
+ @thread.join
161
+
162
+ @logger.log(Logger::ERROR, format(Helpers::Constants::ODP_LOGS[:ODP_EVENT_FAILED], @current_batch.to_json)) unless @current_batch.empty?
163
+ end
164
+
165
+ def running?
166
+ !!@thread && !!@thread.status && !@event_queue.closed?
167
+ end
168
+
169
+ private
170
+
171
+ def run
172
+ loop do
173
+ @mutex.synchronize do
174
+ @received.wait(@mutex, queue_timeout) if @event_queue.empty?
175
+ end
176
+
177
+ begin
178
+ item = @event_queue.pop(true)
179
+ rescue ThreadError => e
180
+ raise unless e.message == 'queue empty'
181
+
182
+ item = nil
183
+ end
184
+
185
+ case item
186
+ when :SHUTDOWN_SIGNAL
187
+ @logger.log(Logger::DEBUG, 'ODP event queue: received shutdown signal.')
188
+ break
189
+
190
+ when :FLUSH_SIGNAL
191
+ @logger.log(Logger::DEBUG, 'ODP event queue: received flush signal.')
192
+ flush_batch!
193
+
194
+ when :UPDATE_CONFIG
195
+ @logger.log(Logger::DEBUG, 'ODP event queue: received update config signal.')
196
+ process_config_update
197
+
198
+ when Optimizely::OdpEvent
199
+ add_to_batch(item)
200
+
201
+ when nil && !@current_batch.empty?
202
+ @logger.log(Logger::DEBUG, 'ODP event queue: flushing on interval.')
203
+ flush_batch!
204
+ end
205
+ end
206
+ rescue SignalException
207
+ @thread_exception = true
208
+ @logger.log(Logger::ERROR, 'Interrupted while processing ODP events.')
209
+ rescue => e
210
+ @thread_exception = true
211
+ @logger.log(Logger::ERROR, "Uncaught exception processing ODP events. Error: #{e.message}")
212
+ ensure
213
+ @logger.log(Logger::INFO, 'Exiting ODP processing loop. Attempting to flush pending events.')
214
+ flush_batch!
215
+ end
216
+
217
+ def flush_batch!
218
+ if @current_batch.empty?
219
+ @logger.log(Logger::DEBUG, 'ODP event queue: nothing to flush.')
220
+ return
221
+ end
222
+
223
+ if @api_key.nil? || @api_host.nil?
224
+ @logger.log(Logger::DEBUG, Helpers::Constants::ODP_LOGS[:ODP_NOT_INTEGRATED])
225
+ @current_batch.clear
226
+ return
227
+ end
228
+
229
+ @logger.log(Logger::DEBUG, "ODP event queue: flushing batch size #{@current_batch.length}.")
230
+ should_retry = false
231
+
232
+ i = 0
233
+ while i < @retry_count
234
+ begin
235
+ should_retry = @api_manager.send_odp_events(@api_key, @api_host, @current_batch)
236
+ rescue StandardError => e
237
+ should_retry = false
238
+ @logger.log(Logger::ERROR, format(Helpers::Constants::ODP_LOGS[:ODP_EVENT_FAILED], "Error: #{e.message} #{@current_batch.to_json}"))
239
+ end
240
+ break unless should_retry
241
+
242
+ @logger.log(Logger::DEBUG, 'Error dispatching ODP events, scheduled to retry.') if i < @retry_count
243
+ i += 1
244
+ end
245
+
246
+ @logger.log(Logger::ERROR, format(Helpers::Constants::ODP_LOGS[:ODP_EVENT_FAILED], "Failed after #{i} retries: #{@current_batch.to_json}")) if should_retry
247
+
248
+ @current_batch.clear
249
+ end
250
+
251
+ def add_to_batch(event)
252
+ set_flush_deadline if @current_batch.empty?
253
+
254
+ @current_batch << event
255
+ return unless @current_batch.length >= @batch_size
256
+
257
+ @logger.log(Logger::DEBUG, 'ODP event queue: flushing on batch size.')
258
+ flush_batch!
259
+ end
260
+
261
+ def set_flush_deadline
262
+ # Sets time that next flush will occur.
263
+ @flush_deadline = Time.new + @flush_interval
264
+ end
265
+
266
+ def time_till_flush
267
+ # Returns seconds until next flush; no less than 0.
268
+ [0, @flush_deadline - Time.new].max
269
+ end
270
+
271
+ def queue_timeout
272
+ # Returns seconds until next flush or None if current batch is empty.
273
+ return nil if @current_batch.empty?
274
+
275
+ time_till_flush
276
+ end
277
+
278
+ def process_config_update
279
+ # Updates the configuration used to send events.
280
+ flush_batch! unless @current_batch.empty?
281
+
282
+ @api_key = @odp_config&.api_key
283
+ @api_host = @odp_config&.api_host
284
+ end
285
+ end
286
+ end