Skip to content

Commit 841e7e2

Browse files
authored
fix: fetch timeout made configurable (#319)
* fetch timeout made configurable * rename timeout variable * Update odp_manager.rb * fix * Update sdk_settings.rb * Update sdk_settings.rb * Update odp_manager.rb * odp event timeout implemented * Update odp_manager.rb * fix * accessor variable synatax fix * Update sdk_settings.rb * unit test fixed * lint fix * refactoring and unit tests added * lint fix
1 parent f1b27d1 commit 841e7e2

12 files changed

+77
-24
lines changed

lib/optimizely.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ def initialize( # rubocop:disable Metrics/ParameterLists
112112
segment_manager: @sdk_settings.odp_segment_manager,
113113
event_manager: @sdk_settings.odp_event_manager,
114114
segments_cache: @sdk_settings.odp_segments_cache,
115+
fetch_segments_timeout: @sdk_settings.fetch_segments_timeout,
116+
odp_event_timeout: @sdk_settings.odp_event_timeout,
115117
logger: @logger
116118
)
117119

lib/optimizely/helpers/sdk_settings.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
module Optimizely
2222
module Helpers
2323
class OptimizelySdkSettings
24-
attr_accessor :odp_disabled, :segments_cache_size, :segments_cache_timeout_in_secs, :odp_segments_cache, :odp_segment_manager, :odp_event_manager
24+
attr_accessor :odp_disabled, :segments_cache_size, :segments_cache_timeout_in_secs, :odp_segments_cache, :odp_segment_manager, :odp_event_manager, :fetch_segments_timeout, :odp_event_timeout
2525

2626
# Contains configuration used for Optimizely Project initialization.
2727
#
@@ -31,20 +31,26 @@ class OptimizelySdkSettings
3131
# @param odp_segments_cache - A custom odp segments cache. Required methods include: `save(key, value)`, `lookup(key) -> value`, and `reset()`
3232
# @param odp_segment_manager - A custom odp segment manager. Required method is: `fetch_qualified_segments(user_key, user_value, options)`.
3333
# @param odp_event_manager - A custom odp event manager. Required method is: `send_event(type:, action:, identifiers:, data:)`
34+
# @param fetch_segments_timeout - The timeout in seconds of to fetch odp segments (optional. default = 10).
35+
# @param odp_event_timeout - The timeout in seconds of to send odp events (optional. default = 10).
3436
def initialize(
3537
disable_odp: false,
3638
segments_cache_size: Constants::ODP_SEGMENTS_CACHE_CONFIG[:DEFAULT_CAPACITY],
3739
segments_cache_timeout_in_secs: Constants::ODP_SEGMENTS_CACHE_CONFIG[:DEFAULT_TIMEOUT_SECONDS],
3840
odp_segments_cache: nil,
3941
odp_segment_manager: nil,
40-
odp_event_manager: nil
42+
odp_event_manager: nil,
43+
fetch_segments_timeout: nil,
44+
odp_event_timeout: nil
4145
)
4246
@odp_disabled = disable_odp
4347
@segments_cache_size = segments_cache_size
4448
@segments_cache_timeout_in_secs = segments_cache_timeout_in_secs
4549
@odp_segments_cache = odp_segments_cache
4650
@odp_segment_manager = odp_segment_manager
4751
@odp_event_manager = odp_event_manager
52+
@fetch_segments_timeout = fetch_segments_timeout
53+
@odp_event_timeout = odp_event_timeout
4854
end
4955
end
5056
end

lib/optimizely/odp/odp_event_api_manager.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ module Optimizely
2222
class OdpEventApiManager
2323
# Interface that handles sending ODP events.
2424

25-
def initialize(logger: nil, proxy_config: nil)
25+
def initialize(logger: nil, proxy_config: nil, timeout: nil)
2626
@logger = logger || NoOpLogger.new
2727
@proxy_config = proxy_config
28+
@timeout = timeout || Optimizely::Helpers::Constants::ODP_REST_API_CONFIG[:REQUEST_TIMEOUT]
2829
end
2930

3031
# Send events to the ODP Events API.
@@ -41,7 +42,7 @@ def send_odp_events(api_key, api_host, events)
4142

4243
begin
4344
response = Helpers::HttpUtils.make_request(
44-
url, :post, events.to_json, headers, Optimizely::Helpers::Constants::ODP_REST_API_CONFIG[:REQUEST_TIMEOUT], @proxy_config
45+
url, :post, events.to_json, headers, @timeout, @proxy_config
4546
)
4647
rescue SocketError, Timeout::Error, Errno::ECONNRESET, Errno::EHOSTUNREACH, Errno::EFAULT, Errno::ENETUNREACH, Errno::ENETDOWN, Errno::ECONNREFUSED
4748
log_failure('network error')

lib/optimizely/odp/odp_event_manager.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ class OdpEventManager
3333
def initialize(
3434
api_manager: nil,
3535
logger: NoOpLogger.new,
36-
proxy_config: nil
36+
proxy_config: nil,
37+
timeout: nil
3738
)
3839
super()
3940

@@ -47,7 +48,7 @@ def initialize(
4748
# received signal should be sent after adding item to event_queue
4849
@received = ConditionVariable.new
4950
@logger = logger
50-
@api_manager = api_manager || OdpEventApiManager.new(logger: @logger, proxy_config: proxy_config)
51+
@api_manager = api_manager || OdpEventApiManager.new(logger: @logger, proxy_config: proxy_config, timeout: timeout)
5152
@batch_size = Helpers::Constants::ODP_EVENT_MANAGER[:DEFAULT_BATCH_SIZE]
5253
@flush_interval = Helpers::Constants::ODP_EVENT_MANAGER[:DEFAULT_FLUSH_INTERVAL_SECONDS]
5354
@flush_deadline = 0

lib/optimizely/odp/odp_manager.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class OdpManager
3232
ODP_CONFIG_STATE = Helpers::Constants::ODP_CONFIG_STATE
3333

3434
# update_odp_config must be called to complete initialization
35-
def initialize(disable:, segments_cache: nil, segment_manager: nil, event_manager: nil, logger: nil)
35+
def initialize(disable:, segments_cache: nil, segment_manager: nil, event_manager: nil, fetch_segments_timeout: nil, odp_event_timeout: nil, logger: nil)
3636
@enabled = !disable
3737
@segment_manager = segment_manager
3838
@event_manager = event_manager
@@ -49,10 +49,10 @@ def initialize(disable:, segments_cache: nil, segment_manager: nil, event_manage
4949
Helpers::Constants::ODP_SEGMENTS_CACHE_CONFIG[:DEFAULT_CAPACITY],
5050
Helpers::Constants::ODP_SEGMENTS_CACHE_CONFIG[:DEFAULT_TIMEOUT_SECONDS]
5151
)
52-
@segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, @logger)
52+
@segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, @logger, timeout: fetch_segments_timeout)
5353
end
5454

55-
@event_manager ||= Optimizely::OdpEventManager.new(logger: @logger)
55+
@event_manager ||= Optimizely::OdpEventManager.new(logger: @logger, timeout: odp_event_timeout)
5656

5757
@segment_manager.odp_config = @odp_config
5858
end

lib/optimizely/odp/odp_segment_api_manager.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ module Optimizely
2222
class OdpSegmentApiManager
2323
# Interface that handles fetching audience segments.
2424

25-
def initialize(logger: nil, proxy_config: nil)
25+
def initialize(logger: nil, proxy_config: nil, timeout: nil)
2626
@logger = logger || NoOpLogger.new
2727
@proxy_config = proxy_config
28+
@timeout = timeout || Optimizely::Helpers::Constants::ODP_GRAPHQL_API_CONFIG[:REQUEST_TIMEOUT]
2829
end
2930

3031
# Fetch segments from the ODP GraphQL API.
@@ -52,7 +53,7 @@ def fetch_segments(api_key, api_host, user_key, user_value, segments_to_check)
5253

5354
begin
5455
response = Helpers::HttpUtils.make_request(
55-
url, :post, payload, headers, Optimizely::Helpers::Constants::ODP_GRAPHQL_API_CONFIG[:REQUEST_TIMEOUT], @proxy_config
56+
url, :post, payload, headers, @timeout, @proxy_config
5657
)
5758
rescue SocketError, Timeout::Error, Net::ProtocolError, Errno::ECONNRESET => e
5859
@logger.log(Logger::DEBUG, "GraphQL download failed: #{e}")

lib/optimizely/odp/odp_segment_manager.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ class OdpSegmentManager
2525
attr_accessor :odp_config
2626
attr_reader :segments_cache, :api_manager, :logger
2727

28-
def initialize(segments_cache, api_manager = nil, logger = nil, proxy_config = nil)
28+
def initialize(segments_cache, api_manager = nil, logger = nil, proxy_config = nil, timeout: nil)
2929
@odp_config = nil
3030
@logger = logger || NoOpLogger.new
31-
@api_manager = api_manager || OdpSegmentApiManager.new(logger: @logger, proxy_config: proxy_config)
31+
@api_manager = api_manager || OdpSegmentApiManager.new(logger: @logger, proxy_config: proxy_config, timeout: timeout)
3232
@segments_cache = segments_cache
3333
end
3434

spec/odp/odp_event_api_manager_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,28 @@
5454
expect(should_retry).to be false
5555
end
5656

57+
it 'should send timeout with custom timeout' do
58+
stub_request(:post, "#{api_host}/v3/events")
59+
.with(
60+
headers: {'content-type': 'application/json', 'x-api-key': api_key},
61+
body: events.to_json
62+
).to_return(status: 200)
63+
64+
api_manager = Optimizely::OdpEventApiManager.new(timeout: 14)
65+
expect(Optimizely::Helpers::HttpUtils).to receive(:make_request).with(
66+
"#{api_host}/v3/events",
67+
:post,
68+
events.to_json,
69+
{'Content-Type' => 'application/json', 'x-api-key' => api_key},
70+
14,
71+
nil
72+
).and_call_original
73+
74+
should_retry = api_manager.send_odp_events(api_key, api_host, events)
75+
76+
expect(should_retry).to be false
77+
end
78+
5779
it 'should return true on network error' do
5880
allow(Optimizely::Helpers::HttpUtils).to receive(:make_request).and_raise(SocketError)
5981
api_manager = Optimizely::OdpEventApiManager.new(logger: spy_logger)

spec/odp/odp_manager_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@
139139
it 'should ignore cache' do
140140
segments_cache = Optimizely::LRUCache.new(500, 500)
141141
expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything)
142-
segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, spy_logger)
142+
segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, spy_logger, nil)
143143

144144
expect(segment_manager.api_manager)
145145
.to receive(:fetch_segments)

spec/odp/odp_segment_api_manager_spec.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,24 @@
234234
expect(segments).to match_array %w[a b]
235235
end
236236

237+
it 'should send timeout for fetch segments with custom timeout' do
238+
api_manager_with_timeout = Optimizely::OdpSegmentApiManager.new(logger: spy_logger, timeout: 14)
239+
stub_request(:post, "#{api_host}/v3/graphql")
240+
.with(
241+
headers: {'content-type': 'application/json', 'x-api-key': api_key},
242+
body: {query: graphql_query, variables: {userId: user_value, audiences: %w[a b c]}}
243+
)
244+
.to_return(status: 200, body: good_response_data.to_json)
245+
expect(Optimizely::Helpers::HttpUtils).to receive(:make_request).with(anything,
246+
anything,
247+
anything,
248+
anything,
249+
14,
250+
nil).and_call_original
251+
segments = api_manager_with_timeout.fetch_segments(api_key, api_host, user_key, user_value, %w[a b c])
252+
expect(segments).to match_array %w[a b]
253+
end
254+
237255
it 'should get empty array when empty array is given' do
238256
stub_request(:post, "#{api_host}/v3/graphql")
239257
.to_return(status: 200, body: good_empty_response_data.to_json)

0 commit comments

Comments
 (0)