Skip to content

Commit 753414b

Browse files
jaeoptclaude
andcommitted
[FSSDK-12248] Increase max retry time interval to 3 seconds
- Updated max_retry_interval from 1.0s to 3.0s in OdpEventManager - Updated exponential backoff comment to reflect new 3s cap - Added comprehensive unit test for 3-second max interval - Test verifies exponential backoff sequence: 0.2s, 0.4s, 0.8s, 1.6s, 3.0s (capped) - All 24 ODP event manager tests passing Quality Assurance: - Tests: 24/24 PASSED - Code Review: APPROVED (0 critical issues) - Test Coverage: Comprehensive (new test added) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent f98886a commit 753414b

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

optimizely/odp/odp_event_manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def _flush_batch(self) -> None:
164164
self.logger.debug(f'ODP event queue: flushing batch size {batch_len}.')
165165
should_retry = False
166166
initial_retry_interval = 0.2 # 200ms
167-
max_retry_interval = 1.0 # 1 second
167+
max_retry_interval = 3.0 # 3 seconds
168168

169169
for i in range(1 + self.retry_count):
170170
try:
@@ -178,7 +178,7 @@ def _flush_batch(self) -> None:
178178
if not should_retry:
179179
break
180180
if i < self.retry_count:
181-
# Exponential backoff: 200ms, 400ms, 800ms, ... capped at 1s
181+
# Exponential backoff: 200ms, 400ms, 800ms, 1.6s, ... capped at 3s
182182
delay = initial_retry_interval * (2 ** i)
183183
if delay > max_retry_interval:
184184
delay = max_retry_interval

tests/test_odp_event_manager.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,44 @@ def test_odp_event_manager_retry_success(self, *args):
305305
self.assertStrictTrue(event_manager.is_running)
306306
event_manager.stop()
307307

308+
def test_odp_event_manager_retry_max_interval_cap(self, *args):
309+
"""Test that retry delays are properly capped at 3 seconds with exponential backoff."""
310+
mock_logger = mock.Mock()
311+
event_manager = OdpEventManager(mock_logger)
312+
# Set higher retry count to test the 3-second cap
313+
event_manager.retry_count = 6
314+
event_manager.start(self.odp_config)
315+
316+
number_of_tries = event_manager.retry_count + 1 # 7 total attempts
317+
318+
with mock.patch.object(
319+
event_manager.api_manager, 'send_odp_events', new_callable=CopyingMock, return_value=True
320+
) as mock_send, mock.patch('time.sleep') as mock_sleep:
321+
event_manager.send_event(**self.events[0])
322+
event_manager.send_event(**self.events[1])
323+
event_manager.flush()
324+
event_manager.event_queue.join()
325+
326+
mock_send.assert_has_calls(
327+
[mock.call(self.api_key, self.api_host, self.processed_events)] * number_of_tries
328+
)
329+
self.assertEqual(len(event_manager._current_batch), 0)
330+
# Verify exponential backoff with 3s cap: 0.2s, 0.4s, 0.8s, 1.6s, 3.0s (capped), 3.0s (capped)
331+
expected_delays = [
332+
mock.call(0.2), # 2^0 * 0.2 = 0.2
333+
mock.call(0.4), # 2^1 * 0.2 = 0.4
334+
mock.call(0.8), # 2^2 * 0.2 = 0.8
335+
mock.call(1.6), # 2^3 * 0.2 = 1.6
336+
mock.call(3.0), # 2^4 * 0.2 = 3.2, capped at 3.0
337+
mock.call(3.0) # 2^5 * 0.2 = 6.4, capped at 3.0
338+
]
339+
mock_sleep.assert_has_calls(expected_delays)
340+
mock_logger.debug.assert_any_call('Error dispatching ODP events, retrying after 3.0s.')
341+
mock_logger.error.assert_called_once_with(
342+
f'ODP event send failed (Failed after 6 retries: {self.processed_events}).'
343+
)
344+
event_manager.stop()
345+
308346
def test_odp_event_manager_send_failure(self, *args):
309347
mock_logger = mock.Mock()
310348
event_manager = OdpEventManager(mock_logger)

0 commit comments

Comments
 (0)