Retry: sleep_for_retry uses max(wait, delay_max) — inflates small Retry-After to delay_max (60s floor) (#860)#868
Retry: sleep_for_retry uses max(wait, delay_max) — inflates small Retry-After to delay_max (60s floor) (#860)#868peco-engineer-bot[bot] wants to merge 3 commits into
Conversation
…ry-After to delay_max (60s floor) (#860) Signed-off-by: peco-engineer-bot[bot] <3815206+peco-engineer-bot[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Verdict: 1 Low
Looks good — the max → min change correctly makes delay_max a ceiling (matching get_backoff_time) and fixes the reported small-Retry-After inflation. Tests are updated appropriately and new coverage was added; one low-severity note about large Retry-After values now being clamped is filed inline.
Addresses: - #3599845693 at src/databricks/sql/auth/retry.py:300 Signed-off-by: peco-engineer-bot[bot] <peco-engineer-bot[bot]@users.noreply.github.com>
| proposed_wait = self.get_backoff_time() | ||
|
|
||
| proposed_wait = max(proposed_wait, self.delay_max) | ||
| proposed_wait = min(proposed_wait, self.delay_max) |
There was a problem hiding this comment.
The delay_max should not apply to server returned retry_after, that should always be the source of truth. In this function we should just use proposed_wait directly, since for get_backoff_time() it already have proposed_backoff = min(proposed_backoff, self.delay_max).
There was a problem hiding this comment.
Made the change the reviewer asked for.
What changed:
src/databricks/sql/auth/retry.py: Removedproposed_wait = min(proposed_wait, self.delay_max)insleep_for_retry(). The server'sRetry-Afteris now honored as-is, and theget_backoff_time()path already caps itself atdelay_maxinternally — soproposed_waitis used directly, exactly as the reviewer described.tests/unit/test_retry.py: The existingtest_sleep__large_retry_after_is_capped_at_delay_maxencoded the now-incorrect behavior, so I updated it (renamed totest_sleep__large_retry_after_is_honored_as_is) to assert that aRetry-After: 120sleeps for 120s rather than being clamped todelay_max.
All 14 tests in tests/unit/test_retry.py pass.
Pushed 834000b.
Addresses: - #3599995835 at src/databricks/sql/auth/retry.py:300 Signed-off-by: peco-engineer-bot[bot] <peco-engineer-bot[bot]@users.noreply.github.com>
|
@jprakash-db you had mentioned there's a reason why we floor at 60s, can you elaborate? |
Summary
Automated fix for #860 — Retry: sleep_for_retry uses max(wait, delay_max) — inflates small Retry-After to delay_max (60s floor).
In
sleep_for_retry(src/databricks/sql/auth/retry.py) changedproposed_wait = max(proposed_wait, self.delay_max)tomin(...), sodelay_maxacts as a ceiling (matchingget_backoff_time) instead of a floor that inflated small Retry-After values to 60s. Verified with the three reproducing tests plus the full unit suite (493 passed).Root cause & plan
Root cause: In
src/databricks/sql/auth/retry.py,sleep_for_retry(line 300) appliesproposed_wait = max(proposed_wait, self.delay_max).delay_maxis meant as a CEILING on the wait (as the siblingget_backoff_timecorrectly usesmin(proposed_backoff, self.delay_max)with the docstring "Never returns a value larger than self.delay_max"). Usingmaxmakesdelay_maxa FLOOR: a small serverRetry-After(e.g. 2s) is inflated to the fulldelay_max(default 60s in prod config; 30s in unit test fixtures). It also forces the no-Retry-After backoff path to always sleepdelay_maxsinceget_backoff_time()already returns a value <=delay_max. Fix: changemaxtominsodelay_maxcaps (not floors) the wait, matching the suggested fix in the issue and the behavior ofget_backoff_time.Files:
src/databricks/sql/auth/retry.py,tests/unit/test_retry.pyPlanned coverage:
Files changed
src/databricks/sql/auth/retry.pytests/unit/test_retry.pyTest plan
tests/unit/test_retry.py::TestRetry::test_sleep__short_retry_after_is_not_inflated— fails (red) against the original code, passes (green) after the fixtests/unit/test_retry.py::TestRetry::test_sleep__no_retry_after— fails (red) against the original code, passes (green) after the fixtests/unit/test_retry.py::TestRetry::test_sleep__no_retry_after_header__multiple_retries— fails (red) against the original code, passes (green) after the fix🤖 Generated by engineer-bot (bug-fix flow) — review before merge.