Skip to content

fix: honor custom timeout on every attempt in request_with_retry#11998

Open
eeshsaxena wants to merge 5 commits into
deepset-ai:mainfrom
eeshsaxena:fix-request-with-retry-timeout
Open

fix: honor custom timeout on every attempt in request_with_retry#11998
eeshsaxena wants to merge 5 commits into
deepset-ai:mainfrom
eeshsaxena:fix-request-with-retry-timeout

Conversation

@eeshsaxena

Copy link
Copy Markdown

Related Issues

No linked issue - found while reading the retry helper.

Proposed Changes:

request_with_retry and async_request_with_retry respect a custom timeout only on the first attempt; every retry silently falls back to the default of 10 seconds.

The cause is that timeout is popped from the shared kwargs dict inside the @retry-decorated inner run():

def run() -> httpx.Response:
    timeout = kwargs.pop("timeout", 10)   # runs on every attempt
    with httpx.Client() as client:
        res = client.request(**kwargs, timeout=timeout)

run() is re-invoked on each retry and kwargs is captured by closure, so the first attempt removes timeout from kwargs and subsequent attempts get the 10 default. A caller doing request_with_retry(url=..., timeout=30, attempts=3) gets timeout=30 on attempt 1 and timeout=10 on the retries.

The fix pops timeout once, before the retry loop, so it is captured for every attempt. Applied to both the sync and async functions.

How did you test it?

  • Added regression tests to test/utils/test_requests_utils.py (sync and async): the first attempt fails with a retryable error, and the test asserts both the initial attempt and the retry are called with the caller's timeout, not the default. These fail on the current code ([5, 10]) and pass with the fix ([5, 5]).
  • The existing test_..._custom_timeout only asserted the first attempt (assert_called_once_with), which is why this slipped through.
  • Verified empirically by mocking httpx.Client.request to record the per-attempt timeout: current [5, 10, 10] for timeout=5, attempts=3, fixed [5, 5, 5]. Same for the async path.
  • Full file passes (18 tests); ruff check and ruff format clean. Added a release note under releasenotes/notes/.

Notes for the reviewer

No source behavior changes beyond the timeout handling; the only functional change is that retries now use the caller's timeout. An AI assistant helped identify and implement this fix; I reviewed all changes and ran the tests locally.

Checklist

  • I have read the contributors guidelines and the code of conduct.
  • I have updated the related issue with new insights and changes.
  • I have added unit tests and updated the docstrings.
  • I've used one of the conventional commit types for my PR title.
  • I have documented my code.
  • I have added a release note file.
  • I have run pre-commit hooks and fixed any issue.

The inner retried function popped `timeout` from the shared `kwargs` dict, so
after the first attempt it was gone and every retry silently fell back to the
default of 10 seconds. Pop `timeout` once, before the retry loop, so it is
captured for all attempts. Applies to both `request_with_retry` and
`async_request_with_retry`.

Adds regression tests asserting the caller's timeout is used on the retry too.
@eeshsaxena
eeshsaxena requested a review from a team as a code owner July 13, 2026 22:03
@eeshsaxena
eeshsaxena requested review from sjrl and removed request for a team July 13, 2026 22:03
@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

@eeshsaxena is attempting to deploy a commit to the deepset Team on Vercel.

A member of the Team first needs to authorize it.

@CLAassistant

CLAassistant commented Jul 13, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@github-actions github-actions Bot added topic:tests type:documentation Improvements on the docs labels Jul 13, 2026
@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  haystack/core/pipeline
  pipeline.py
  haystack/utils
  requests_utils.py
Project Total  

This report was generated by python-coverage-comment-action

Comment thread haystack/utils/requests_utils.py Outdated
Comment thread haystack/utils/requests_utils.py Outdated
@sjrl sjrl self-assigned this Jul 14, 2026
@eeshsaxena eeshsaxena closed this Jul 16, 2026
@eeshsaxena eeshsaxena reopened this Jul 16, 2026
Comment thread haystack/utils/requests_utils.py Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

topic:tests type:documentation Improvements on the docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants