diff --git a/src/databricks/sql/auth/retry.py b/src/databricks/sql/auth/retry.py index 9cb29fdce..cf18cdfda 100755 --- a/src/databricks/sql/auth/retry.py +++ b/src/databricks/sql/auth/retry.py @@ -297,7 +297,6 @@ def sleep_for_retry(self, response: BaseHTTPResponse) -> bool: else: proposed_wait = self.get_backoff_time() - proposed_wait = max(proposed_wait, self.delay_max) self.check_proposed_wait(proposed_wait) logger.debug(f"Retrying after {proposed_wait} seconds") time.sleep(proposed_wait) diff --git a/tests/unit/test_retry.py b/tests/unit/test_retry.py index 7abab509d..1821f3916 100644 --- a/tests/unit/test_retry.py +++ b/tests/unit/test_retry.py @@ -39,14 +39,32 @@ def test_sleep__no_retry_after(self, t_mock, retry_policy, error_history): retry_policy.history = [error_history, error_history] retry_policy.sleep(HTTPResponse(status=503)) - expected_backoff_time = max( - self.calculate_backoff_time( - 0, retry_policy.delay_min, retry_policy.delay_max - ), - retry_policy.delay_max, + expected_backoff_time = self.calculate_backoff_time( + 0, retry_policy.delay_min, retry_policy.delay_max ) t_mock.assert_called_with(expected_backoff_time) + @patch("time.sleep") + def test_sleep__short_retry_after_is_not_inflated(self, t_mock, retry_policy): + # A small server Retry-After must be honored as-is (delay_max is a + # ceiling, not a floor). delay_max defaults to 30 in these fixtures. + retry_policy._retry_start_time = time.time() + retry_policy.history = [] + retry_policy.sleep(HTTPResponse(status=503, headers={"Retry-After": "2"})) + + t_mock.assert_called_with(2) + + @patch("time.sleep") + def test_sleep__large_retry_after_is_honored_as_is(self, t_mock, retry_policy): + # A server-returned Retry-After is the source of truth and must be + # honored as-is; delay_max does not cap it. delay_max defaults to 30 in + # these fixtures, so 120 would be clamped if the ceiling still applied. + retry_policy._retry_start_time = time.time() + retry_policy.history = [] + retry_policy.sleep(HTTPResponse(status=503, headers={"Retry-After": "120"})) + + t_mock.assert_called_with(120) + @patch("time.sleep") def test_sleep__no_retry_after_header__multiple_retries(self, t_mock, retry_policy): num_attempts = retry_policy.stop_after_attempts_count @@ -62,11 +80,8 @@ def test_sleep__no_retry_after_header__multiple_retries(self, t_mock, retry_poli expected_backoff_times = [] for attempt in range(num_attempts): expected_backoff_times.append( - max( - self.calculate_backoff_time( - attempt, retry_policy.delay_min, retry_policy.delay_max - ), - retry_policy.delay_max, + self.calculate_backoff_time( + attempt, retry_policy.delay_min, retry_policy.delay_max ) )