optimizely-sdk 3.3.1 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/lib/optimizely.rb +199 -38
- data/lib/optimizely/audience.rb +2 -2
- data/lib/optimizely/config/datafile_project_config.rb +15 -3
- data/lib/optimizely/config/proxy_config.rb +34 -0
- data/lib/optimizely/config_manager/async_scheduler.rb +8 -4
- data/lib/optimizely/config_manager/http_project_config_manager.rb +50 -28
- data/lib/optimizely/config_manager/static_project_config_manager.rb +6 -2
- data/lib/optimizely/event/batch_event_processor.rb +67 -58
- data/lib/optimizely/event_dispatcher.rb +35 -17
- data/lib/optimizely/exceptions.rb +8 -9
- data/lib/optimizely/helpers/constants.rb +6 -3
- data/lib/optimizely/helpers/http_utils.rb +64 -0
- data/lib/optimizely/helpers/variable_type.rb +8 -1
- data/lib/optimizely/notification_center.rb +13 -5
- data/lib/optimizely/optimizely_config.rb +116 -0
- data/lib/optimizely/optimizely_factory.rb +54 -5
- data/lib/optimizely/version.rb +1 -1
- metadata +6 -18
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#
|
4
|
-
# Copyright 2019, Optimizely and contributors
|
4
|
+
# Copyright 2019-2020, Optimizely and contributors
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
@@ -19,18 +19,21 @@ require_relative '../config/datafile_project_config'
|
|
19
19
|
require_relative '../error_handler'
|
20
20
|
require_relative '../exceptions'
|
21
21
|
require_relative '../helpers/constants'
|
22
|
+
require_relative '../helpers/http_utils'
|
22
23
|
require_relative '../logger'
|
23
24
|
require_relative '../notification_center'
|
24
25
|
require_relative '../project_config'
|
26
|
+
require_relative '../optimizely_config'
|
25
27
|
require_relative 'project_config_manager'
|
26
28
|
require_relative 'async_scheduler'
|
27
|
-
|
29
|
+
|
28
30
|
require 'json'
|
31
|
+
|
29
32
|
module Optimizely
|
30
33
|
class HTTPProjectConfigManager < ProjectConfigManager
|
31
34
|
# Config manager that polls for the datafile and updated ProjectConfig based on an update interval.
|
32
35
|
|
33
|
-
attr_reader :stopped
|
36
|
+
attr_reader :stopped, :optimizely_config
|
34
37
|
|
35
38
|
# Initialize config manager. One of sdk_key or url has to be set to be able to use.
|
36
39
|
#
|
@@ -48,6 +51,8 @@ module Optimizely
|
|
48
51
|
# error_handler - Provides a handle_error method to handle exceptions.
|
49
52
|
# skip_json_validation - Optional boolean param which allows skipping JSON schema
|
50
53
|
# validation upon object invocation. By default JSON schema validation will be performed.
|
54
|
+
# datafile_access_token - access token used to fetch private datafiles
|
55
|
+
# proxy_config - Optional proxy config instancea to configure making web requests through a proxy server.
|
51
56
|
def initialize(
|
52
57
|
sdk_key: nil,
|
53
58
|
url: nil,
|
@@ -60,24 +65,31 @@ module Optimizely
|
|
60
65
|
logger: nil,
|
61
66
|
error_handler: nil,
|
62
67
|
skip_json_validation: false,
|
63
|
-
notification_center: nil
|
68
|
+
notification_center: nil,
|
69
|
+
datafile_access_token: nil,
|
70
|
+
proxy_config: nil
|
64
71
|
)
|
65
72
|
@logger = logger || NoOpLogger.new
|
66
73
|
@error_handler = error_handler || NoOpErrorHandler.new
|
74
|
+
@access_token = datafile_access_token
|
67
75
|
@datafile_url = get_datafile_url(sdk_key, url, url_template)
|
68
76
|
@polling_interval = nil
|
69
77
|
polling_interval(polling_interval)
|
70
78
|
@blocking_timeout = nil
|
71
79
|
blocking_timeout(blocking_timeout)
|
72
80
|
@last_modified = nil
|
73
|
-
@async_scheduler = AsyncScheduler.new(method(:fetch_datafile_config), @polling_interval, auto_update, @logger)
|
74
|
-
@async_scheduler.start! if start_by_default == true
|
75
|
-
@stopped = false
|
76
81
|
@skip_json_validation = skip_json_validation
|
77
82
|
@notification_center = notification_center.is_a?(Optimizely::NotificationCenter) ? notification_center : NotificationCenter.new(@logger, @error_handler)
|
78
83
|
@config = datafile.nil? ? nil : DatafileProjectConfig.create(datafile, @logger, @error_handler, @skip_json_validation)
|
84
|
+
@optimizely_config = @config.nil? ? nil : OptimizelyConfig.new(@config).config
|
79
85
|
@mutex = Mutex.new
|
80
86
|
@resource = ConditionVariable.new
|
87
|
+
@async_scheduler = AsyncScheduler.new(method(:fetch_datafile_config), @polling_interval, auto_update, @logger)
|
88
|
+
# Start async scheduler in the end to avoid race condition where scheduler executes
|
89
|
+
# callback which makes use of variables not yet initialized by the main thread.
|
90
|
+
@async_scheduler.start! if start_by_default == true
|
91
|
+
@proxy_config = proxy_config
|
92
|
+
@stopped = false
|
81
93
|
end
|
82
94
|
|
83
95
|
def ready?
|
@@ -139,21 +151,20 @@ module Optimizely
|
|
139
151
|
end
|
140
152
|
|
141
153
|
def request_config
|
142
|
-
@logger.log(
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
headers = {
|
148
|
-
'Content-Type' => 'application/json'
|
149
|
-
}
|
154
|
+
@logger.log(Logger::DEBUG, "Fetching datafile from #{@datafile_url}")
|
155
|
+
headers = {}
|
156
|
+
headers['Content-Type'] = 'application/json'
|
157
|
+
headers['If-Modified-Since'] = @last_modified if @last_modified
|
158
|
+
headers['Authorization'] = "Bearer #{@access_token}" unless @access_token.nil?
|
150
159
|
|
151
|
-
|
160
|
+
# Cleaning headers before logging to avoid exposing authorization token
|
161
|
+
cleansed_headers = {}
|
162
|
+
headers.each { |key, value| cleansed_headers[key] = key == 'Authorization' ? '********' : value }
|
163
|
+
@logger.log(Logger::DEBUG, "Datafile request headers: #{cleansed_headers}")
|
152
164
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
timeout: Helpers::Constants::CONFIG_MANAGER['REQUEST_TIMEOUT']
|
165
|
+
begin
|
166
|
+
response = Helpers::HttpUtils.make_request(
|
167
|
+
@datafile_url, :get, nil, headers, Helpers::Constants::CONFIG_MANAGER['REQUEST_TIMEOUT'], @proxy_config
|
157
168
|
)
|
158
169
|
rescue StandardError => e
|
159
170
|
@logger.log(
|
@@ -163,6 +174,9 @@ module Optimizely
|
|
163
174
|
return nil
|
164
175
|
end
|
165
176
|
|
177
|
+
response_code = response.code.to_i
|
178
|
+
@logger.log(Logger::DEBUG, "Datafile response status code #{response_code}")
|
179
|
+
|
166
180
|
# Leave datafile and config unchanged if it has not been modified.
|
167
181
|
if response.code == '304'
|
168
182
|
@logger.log(
|
@@ -172,9 +186,14 @@ module Optimizely
|
|
172
186
|
return
|
173
187
|
end
|
174
188
|
|
175
|
-
|
176
|
-
|
177
|
-
|
189
|
+
if response_code >= 200 && response_code < 400
|
190
|
+
@logger.log(Logger::DEBUG, 'Successfully fetched datafile, generating Project config')
|
191
|
+
config = DatafileProjectConfig.create(response.body, @logger, @error_handler, @skip_json_validation)
|
192
|
+
@last_modified = response[Helpers::Constants::HTTP_HEADERS['LAST_MODIFIED']]
|
193
|
+
@logger.log(Logger::DEBUG, "Saved last modified header value from response: #{@last_modified}.")
|
194
|
+
else
|
195
|
+
@logger.log(Logger::DEBUG, "Datafile fetch failed, status: #{response.code}, message: #{response.message}")
|
196
|
+
end
|
178
197
|
|
179
198
|
config
|
180
199
|
end
|
@@ -190,6 +209,7 @@ module Optimizely
|
|
190
209
|
end
|
191
210
|
|
192
211
|
@config = config
|
212
|
+
@optimizely_config = OptimizelyConfig.new(config).config
|
193
213
|
|
194
214
|
@notification_center.send_notifications(NotificationCenter::NOTIFICATION_TYPES[:OPTIMIZELY_CONFIG_UPDATE])
|
195
215
|
|
@@ -279,17 +299,19 @@ module Optimizely
|
|
279
299
|
# SDK key to determine URL from which to fetch the datafile.
|
280
300
|
# Returns String representing URL to fetch datafile from.
|
281
301
|
if sdk_key.nil? && url.nil?
|
282
|
-
|
283
|
-
@
|
302
|
+
error_msg = 'Must provide at least one of sdk_key or url.'
|
303
|
+
@logger.log(Logger::ERROR, error_msg)
|
304
|
+
@error_handler.handle_error(InvalidInputsError.new(error_msg))
|
284
305
|
end
|
285
306
|
|
286
307
|
unless url
|
287
|
-
url_template ||= Helpers::Constants::CONFIG_MANAGER['DATAFILE_URL_TEMPLATE']
|
308
|
+
url_template ||= @access_token.nil? ? Helpers::Constants::CONFIG_MANAGER['DATAFILE_URL_TEMPLATE'] : Helpers::Constants::CONFIG_MANAGER['AUTHENTICATED_DATAFILE_URL_TEMPLATE']
|
288
309
|
begin
|
289
310
|
return (url_template % sdk_key)
|
290
311
|
rescue
|
291
|
-
|
292
|
-
@
|
312
|
+
error_msg = "Invalid url_template #{url_template} provided."
|
313
|
+
@logger.log(Logger::ERROR, error_msg)
|
314
|
+
@error_handler.handle_error(InvalidInputsError.new(error_msg))
|
293
315
|
end
|
294
316
|
end
|
295
317
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#
|
4
|
-
# Copyright 2019, Optimizely and contributors
|
4
|
+
# Copyright 2019-2020, Optimizely and contributors
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
@@ -17,11 +17,13 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
require_relative '../config/datafile_project_config'
|
20
|
+
require_relative '../optimizely_config'
|
20
21
|
require_relative 'project_config_manager'
|
22
|
+
|
21
23
|
module Optimizely
|
22
24
|
class StaticProjectConfigManager < ProjectConfigManager
|
23
25
|
# Implementation of ProjectConfigManager interface.
|
24
|
-
attr_reader :config
|
26
|
+
attr_reader :config, :optimizely_config
|
25
27
|
|
26
28
|
def initialize(datafile, logger, error_handler, skip_json_validation)
|
27
29
|
# Looks up and sets datafile and config based on response body.
|
@@ -38,6 +40,8 @@ module Optimizely
|
|
38
40
|
error_handler,
|
39
41
|
skip_json_validation
|
40
42
|
)
|
43
|
+
|
44
|
+
@optimizely_config = @config.nil? ? nil : OptimizelyConfig.new(@config).config
|
41
45
|
end
|
42
46
|
end
|
43
47
|
end
|
@@ -20,7 +20,7 @@ require_relative '../helpers/validator'
|
|
20
20
|
module Optimizely
|
21
21
|
class BatchEventProcessor < EventProcessor
|
22
22
|
# BatchEventProcessor is a batched implementation of the Interface EventProcessor.
|
23
|
-
# Events passed to the BatchEventProcessor are immediately added to
|
23
|
+
# Events passed to the BatchEventProcessor are immediately added to an EventQueue.
|
24
24
|
# The BatchEventProcessor maintains a single consumer thread that pulls events off of
|
25
25
|
# the BlockingQueue and buffers them for either a configured batch size or for a
|
26
26
|
# maximum duration before the resulting LogEvent is sent to the NotificationCenter.
|
@@ -30,13 +30,14 @@ module Optimizely
|
|
30
30
|
DEFAULT_BATCH_SIZE = 10
|
31
31
|
DEFAULT_BATCH_INTERVAL = 30_000 # interval in milliseconds
|
32
32
|
DEFAULT_QUEUE_CAPACITY = 1000
|
33
|
+
DEFAULT_TIMEOUT_INTERVAL = 5 # interval in seconds
|
33
34
|
|
34
35
|
FLUSH_SIGNAL = 'FLUSH_SIGNAL'
|
35
36
|
SHUTDOWN_SIGNAL = 'SHUTDOWN_SIGNAL'
|
36
37
|
|
37
38
|
def initialize(
|
38
39
|
event_queue: SizedQueue.new(DEFAULT_QUEUE_CAPACITY),
|
39
|
-
event_dispatcher:
|
40
|
+
event_dispatcher: nil,
|
40
41
|
batch_size: DEFAULT_BATCH_SIZE,
|
41
42
|
flush_interval: DEFAULT_BATCH_INTERVAL,
|
42
43
|
logger: NoOpLogger.new,
|
@@ -44,7 +45,7 @@ module Optimizely
|
|
44
45
|
)
|
45
46
|
@event_queue = event_queue
|
46
47
|
@logger = logger
|
47
|
-
@event_dispatcher = event_dispatcher
|
48
|
+
@event_dispatcher = event_dispatcher || EventDispatcher.new(logger: @logger)
|
48
49
|
@batch_size = if (batch_size.is_a? Integer) && positive_number?(batch_size)
|
49
50
|
batch_size
|
50
51
|
else
|
@@ -58,11 +59,9 @@ module Optimizely
|
|
58
59
|
DEFAULT_BATCH_INTERVAL
|
59
60
|
end
|
60
61
|
@notification_center = notification_center
|
61
|
-
@mutex = Mutex.new
|
62
|
-
@received = ConditionVariable.new
|
63
62
|
@current_batch = []
|
64
63
|
@started = false
|
65
|
-
|
64
|
+
@stopped = false
|
66
65
|
end
|
67
66
|
|
68
67
|
def start!
|
@@ -71,76 +70,61 @@ module Optimizely
|
|
71
70
|
return
|
72
71
|
end
|
73
72
|
@flushing_interval_deadline = Helpers::DateTimeUtils.create_timestamp + @flush_interval
|
74
|
-
@
|
73
|
+
@logger.log(Logger::INFO, 'Starting scheduler.')
|
74
|
+
if @wait_mutex.nil?
|
75
|
+
@wait_mutex = Mutex.new
|
76
|
+
@resource = ConditionVariable.new
|
77
|
+
end
|
78
|
+
@thread = Thread.new { run_queue }
|
75
79
|
@started = true
|
80
|
+
@stopped = false
|
76
81
|
end
|
77
82
|
|
78
83
|
def flush
|
79
|
-
@
|
80
|
-
|
81
|
-
@received.signal
|
82
|
-
end
|
84
|
+
@event_queue << FLUSH_SIGNAL
|
85
|
+
@wait_mutex.synchronize { @resource.signal }
|
83
86
|
end
|
84
87
|
|
85
88
|
def process(user_event)
|
86
89
|
@logger.log(Logger::DEBUG, "Received userEvent: #{user_event}")
|
87
90
|
|
88
|
-
if
|
91
|
+
# if the processor has been explicitly stopped. Don't accept tasks
|
92
|
+
if @stopped
|
89
93
|
@logger.log(Logger::WARN, 'Executor shutdown, not accepting tasks.')
|
90
94
|
return
|
91
95
|
end
|
92
96
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
97
|
+
# start if the processor hasn't been started
|
98
|
+
start! unless @started
|
99
|
+
|
100
|
+
begin
|
101
|
+
@event_queue.push(user_event, true)
|
102
|
+
@wait_mutex.synchronize { @resource.signal }
|
103
|
+
rescue => e
|
104
|
+
@logger.log(Logger::WARN, 'Payload not accepted by the queue: ' + e.message)
|
105
|
+
return
|
101
106
|
end
|
102
107
|
end
|
103
108
|
|
104
109
|
def stop!
|
105
110
|
return unless @started
|
106
111
|
|
107
|
-
@
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
+
@logger.log(Logger::INFO, 'Stopping scheduler.')
|
113
|
+
@event_queue << SHUTDOWN_SIGNAL
|
114
|
+
@wait_mutex.synchronize { @resource.signal }
|
115
|
+
@thread.join(DEFAULT_TIMEOUT_INTERVAL)
|
112
116
|
@started = false
|
113
|
-
@
|
114
|
-
@thread.exit
|
117
|
+
@stopped = true
|
115
118
|
end
|
116
119
|
|
117
120
|
private
|
118
121
|
|
119
|
-
def
|
120
|
-
|
121
|
-
|
122
|
-
@logger.log(
|
123
|
-
Logger::DEBUG,
|
124
|
-
'Deadline exceeded flushing current batch.'
|
125
|
-
)
|
126
|
-
flush_queue!
|
127
|
-
end
|
128
|
-
|
129
|
-
item = nil
|
130
|
-
|
131
|
-
@mutex.synchronize do
|
132
|
-
@received.wait(@mutex, 0.05)
|
133
|
-
item = @event_queue.pop if @event_queue.length.positive?
|
134
|
-
end
|
135
|
-
|
136
|
-
if item.nil?
|
137
|
-
sleep(0.05)
|
138
|
-
next
|
139
|
-
end
|
140
|
-
|
122
|
+
def process_queue
|
123
|
+
while @event_queue.length.positive?
|
124
|
+
item = @event_queue.pop
|
141
125
|
if item == SHUTDOWN_SIGNAL
|
142
|
-
@logger.log(Logger::
|
143
|
-
|
126
|
+
@logger.log(Logger::DEBUG, 'Received shutdown signal.')
|
127
|
+
return false
|
144
128
|
end
|
145
129
|
|
146
130
|
if item == FLUSH_SIGNAL
|
@@ -151,15 +135,35 @@ module Optimizely
|
|
151
135
|
|
152
136
|
add_to_batch(item) if item.is_a? Optimizely::UserEvent
|
153
137
|
end
|
138
|
+
true
|
139
|
+
end
|
140
|
+
|
141
|
+
def run_queue
|
142
|
+
loop do
|
143
|
+
if Helpers::DateTimeUtils.create_timestamp >= @flushing_interval_deadline
|
144
|
+
@logger.log(Logger::DEBUG, 'Deadline exceeded flushing current batch.')
|
145
|
+
|
146
|
+
break unless process_queue
|
147
|
+
|
148
|
+
flush_queue!
|
149
|
+
@flushing_interval_deadline = Helpers::DateTimeUtils.create_timestamp + @flush_interval
|
150
|
+
end
|
151
|
+
|
152
|
+
break unless process_queue
|
153
|
+
|
154
|
+
# what is the current interval to flush in seconds
|
155
|
+
interval = (@flushing_interval_deadline - Helpers::DateTimeUtils.create_timestamp) * 0.001
|
156
|
+
|
157
|
+
next unless interval.positive?
|
158
|
+
|
159
|
+
@wait_mutex.synchronize { @resource.wait(@wait_mutex, interval) }
|
160
|
+
end
|
154
161
|
rescue SignalException
|
155
|
-
@logger.log(Logger::
|
156
|
-
rescue
|
162
|
+
@logger.log(Logger::ERROR, 'Interrupted while processing buffer.')
|
163
|
+
rescue => e
|
157
164
|
@logger.log(Logger::ERROR, "Uncaught exception processing buffer. #{e.message}")
|
158
165
|
ensure
|
159
|
-
@logger.log(
|
160
|
-
Logger::INFO,
|
161
|
-
'Exiting processing loop. Attempting to flush pending events.'
|
162
|
-
)
|
166
|
+
@logger.log(Logger::INFO, 'Exiting processing loop. Attempting to flush pending events.')
|
163
167
|
flush_queue!
|
164
168
|
end
|
165
169
|
|
@@ -168,6 +172,11 @@ module Optimizely
|
|
168
172
|
|
169
173
|
log_event = Optimizely::EventFactory.create_log_event(@current_batch, @logger)
|
170
174
|
begin
|
175
|
+
@logger.log(
|
176
|
+
Logger::INFO,
|
177
|
+
'Flushing Queue.'
|
178
|
+
)
|
179
|
+
|
171
180
|
@event_dispatcher.dispatch_event(log_event)
|
172
181
|
@notification_center&.send_notifications(
|
173
182
|
NotificationCenter::NOTIFICATION_TYPES[:LOG_EVENT],
|
@@ -192,7 +201,7 @@ module Optimizely
|
|
192
201
|
@current_batch << user_event
|
193
202
|
return unless @current_batch.length >= @batch_size
|
194
203
|
|
195
|
-
@logger.log(Logger::DEBUG, 'Flushing on max batch size
|
204
|
+
@logger.log(Logger::DEBUG, 'Flushing on max batch size.')
|
196
205
|
flush_queue!
|
197
206
|
end
|
198
207
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#
|
4
|
-
# Copyright 2016-2017, Optimizely and contributors
|
4
|
+
# Copyright 2016-2017, 2019-2020 Optimizely and contributors
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
@@ -15,7 +15,8 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
|
-
|
18
|
+
require_relative 'exceptions'
|
19
|
+
require_relative 'helpers/http_utils'
|
19
20
|
|
20
21
|
module Optimizely
|
21
22
|
class NoOpEventDispatcher
|
@@ -28,26 +29,43 @@ module Optimizely
|
|
28
29
|
# @api constants
|
29
30
|
REQUEST_TIMEOUT = 10
|
30
31
|
|
32
|
+
def initialize(logger: nil, error_handler: nil, proxy_config: nil)
|
33
|
+
@logger = logger || NoOpLogger.new
|
34
|
+
@error_handler = error_handler || NoOpErrorHandler.new
|
35
|
+
@proxy_config = proxy_config
|
36
|
+
end
|
37
|
+
|
31
38
|
# Dispatch the event being represented by the Event object.
|
32
39
|
#
|
33
40
|
# @param event - Event object
|
34
41
|
def dispatch_event(event)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
42
|
+
response = Helpers::HttpUtils.make_request(
|
43
|
+
event.url, event.http_verb, event.params.to_json, event.headers, REQUEST_TIMEOUT, @proxy_config
|
44
|
+
)
|
45
|
+
|
46
|
+
error_msg = "Event failed to dispatch with response code: #{response.code}"
|
47
|
+
|
48
|
+
case response.code.to_i
|
49
|
+
when 400...500
|
50
|
+
@logger.log(Logger::ERROR, error_msg)
|
51
|
+
@error_handler.handle_error(HTTPCallError.new("HTTP Client Error: #{response.code}"))
|
52
|
+
|
53
|
+
when 500...600
|
54
|
+
@logger.log(Logger::ERROR, error_msg)
|
55
|
+
@error_handler.handle_error(HTTPCallError.new("HTTP Server Error: #{response.code}"))
|
56
|
+
else
|
57
|
+
@logger.log(Logger::DEBUG, 'event successfully sent with response code ' + response.code.to_s)
|
50
58
|
end
|
59
|
+
rescue Timeout::Error => e
|
60
|
+
@logger.log(Logger::ERROR, "Request Timed out. Error: #{e}")
|
61
|
+
@error_handler.handle_error(e)
|
62
|
+
|
63
|
+
# Returning Timeout error to retain existing behavior.
|
64
|
+
e
|
65
|
+
rescue StandardError => e
|
66
|
+
@logger.log(Logger::ERROR, "Event failed to dispatch. Error: #{e}")
|
67
|
+
@error_handler.handle_error(e)
|
68
|
+
nil
|
51
69
|
end
|
52
70
|
end
|
53
71
|
end
|