Skip to content

Commit 3856d58

Browse files
j7nw4rJohnathan WalkerCopilot
authored andcommitted
[ServiceBus] Fix flaky test_backoff_fixed_retry by mocking time.sleep (Azure#46987)
The test previously measured wall-clock time around real time.sleep(0.8) calls and asserted the duration was strictly less than 1.6 seconds. On slow CI agents (notably macOS hosts) the elapsed time can exceed the budget by a few ms (e.g., 1.6399s observed in PR Azure#46953), causing intermittent failures. Mock time.sleep in azure.servicebus._base_handler and assert the value passed to sleep instead. This is deterministic and ~80x faster. Co-authored-by: Johnathan Walker <johwalker@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent e50183f commit 3856d58

1 file changed

Lines changed: 26 additions & 50 deletions

File tree

sdk/servicebus/azure-servicebus/tests/test_sb_client.py

Lines changed: 26 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -641,56 +641,32 @@ def test_sb_client_with_ssl_context(
641641

642642
@pytest.mark.parametrize("uamqp_transport", uamqp_transport_params, ids=uamqp_transport_ids)
643643
def test_backoff_fixed_retry(self, uamqp_transport):
644-
645-
client = ServiceBusClient("fake.host.com", "fake_eh", retry_mode="fixed", uamqp_transport=uamqp_transport)
646-
# queue sender
647-
sender = client.get_queue_sender("fake_name")
648-
backoff = client._config.retry_backoff_factor
649-
start_time = time.time()
650-
sender._backoff(retried_times=1, last_exception=Exception("fake"), abs_timeout_time=None)
651-
sleep_time_fixed = time.time() - start_time
652-
# exp = 0.8 * (2 ** 1) = 1.6
653-
# time.sleep() in _backoff will take AT LEAST time 'exp' for retry_mode='exponential'
654-
# check that fixed is less than 'exp'
655-
assert sleep_time_fixed < backoff * (2**1)
656-
657-
# topic sender
658-
sender = client.get_topic_sender("fake_name")
659-
backoff = client._config.retry_backoff_factor
660-
start_time = time.time()
661-
sender._backoff(retried_times=1, last_exception=Exception("fake"), abs_timeout_time=None)
662-
sleep_time_fixed = time.time() - start_time
663-
assert sleep_time_fixed < backoff * (2**1)
664-
665-
# queue receiver
666-
receiver = client.get_queue_receiver("fake_name")
667-
backoff = client._config.retry_backoff_factor
668-
start_time = time.time()
669-
receiver._backoff(retried_times=1, last_exception=Exception("fake"), abs_timeout_time=None)
670-
sleep_time_fixed = time.time() - start_time
671-
assert sleep_time_fixed < backoff * (2**1)
672-
673-
# subscription receiver
674-
receiver = client.get_subscription_receiver("fake_topic", "fake_sub")
675-
backoff = client._config.retry_backoff_factor
676-
start_time = time.time()
677-
receiver._backoff(retried_times=1, last_exception=Exception("fake"), abs_timeout_time=None)
678-
sleep_time_fixed = time.time() - start_time
679-
assert sleep_time_fixed < backoff * (2**1)
680-
681-
client = ServiceBusClient(
682-
"fake.host.com", "fake_eh", retry_mode=RetryMode.Fixed, uamqp_transport=uamqp_transport
683-
)
684-
# queue sender
685-
sender = client.get_queue_sender("fake_name")
686-
backoff = client._config.retry_backoff_factor
687-
start_time = time.time()
688-
sender._backoff(retried_times=1, last_exception=Exception("fake"), abs_timeout_time=None)
689-
sleep_time_fixed = time.time() - start_time
690-
# exp = 0.8 * (2 ** 1) = 1.6
691-
# time.sleep() in _backoff will take AT LEAST time 'exp' for retry_mode='exponential'
692-
# check that fixed is less than 'exp'
693-
assert sleep_time_fixed < backoff * (2**1)
644+
# Patch time.sleep inside _base_handler so the test is deterministic and
645+
# not subject to OS scheduling jitter (previously this measured wall-clock
646+
# time around real sleeps which caused flakes on slow CI agents).
647+
from unittest import mock
648+
649+
def _assert_fixed_backoff(handler):
650+
backoff = handler._config.retry_backoff_factor
651+
with mock.patch("azure.servicebus._base_handler.time.sleep") as mocked_sleep:
652+
handler._backoff(retried_times=1, last_exception=Exception("fake"), abs_timeout_time=None)
653+
# _backoff should sleep exactly once with the fixed backoff value.
654+
mocked_sleep.assert_called_once()
655+
(slept,), _ = mocked_sleep.call_args
656+
# In 'fixed' mode the sleep should equal `backoff` (i.e. 0.8), and in
657+
# particular must be strictly less than what 'exponential' would use
658+
# at retried_times=1: backoff * (2 ** 1).
659+
assert slept == backoff
660+
assert slept < backoff * (2**1)
661+
662+
for retry_mode in ("fixed", RetryMode.Fixed):
663+
client = ServiceBusClient(
664+
"fake.host.com", "fake_eh", retry_mode=retry_mode, uamqp_transport=uamqp_transport
665+
)
666+
_assert_fixed_backoff(client.get_queue_sender("fake_name"))
667+
_assert_fixed_backoff(client.get_topic_sender("fake_name"))
668+
_assert_fixed_backoff(client.get_queue_receiver("fake_name"))
669+
_assert_fixed_backoff(client.get_subscription_receiver("fake_topic", "fake_sub"))
694670

695671
@pytest.mark.parametrize("uamqp_transport", uamqp_transport_params, ids=uamqp_transport_ids)
696672
def test_custom_client_id_queue_sender(self, uamqp_transport, **kwargs):

0 commit comments

Comments
 (0)