diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index cf4571bf45..8b4ec999a0 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -1085,13 +1085,8 @@ def _sleep_for_retry( self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None ) -> None: remaining_retries = max_retries - retries_taken - if remaining_retries == 1: - log.debug("1 retry left") - else: - log.debug("%i retries left", remaining_retries) - timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) - log.info("Retrying request to %s in %f seconds", options.url, timeout) + log.info("Retrying request to %s in %f seconds (%i/%i)", options.url, timeout, retries_taken + 1, max_retries) time.sleep(timeout) @@ -1684,13 +1679,8 @@ async def _sleep_for_retry( self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None ) -> None: remaining_retries = max_retries - retries_taken - if remaining_retries == 1: - log.debug("1 retry left") - else: - log.debug("%i retries left", remaining_retries) - timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) - log.info("Retrying request to %s in %f seconds", options.url, timeout) + log.info("Retrying request to %s in %f seconds (%i/%i)", options.url, timeout, retries_taken + 1, max_retries) await anyio.sleep(timeout) diff --git a/tests/test_client.py b/tests/test_client.py index a015cd7d40..d921d45bfb 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -6,6 +6,7 @@ import os import sys import json +import logging import asyncio import inspect import dataclasses @@ -938,6 +939,38 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + def test_retry_log_includes_attempt_count( + self, client: OpenAI, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture + ) -> None: + client = client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < 2: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/chat/completions").mock(side_effect=retry_handler) + + with caplog.at_level(logging.INFO): + client.chat.completions.with_raw_response.create( + messages=[ + { + "content": "string", + "role": "developer", + } + ], + model="gpt-5.4", + ) + + assert any("Retrying request to /chat/completions" in message and "(1/4)" in message for message in caplog.messages) + assert any("Retrying request to /chat/completions" in message and "(2/4)" in message for message in caplog.messages) + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) @@ -1985,6 +2018,38 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + async def test_retry_log_includes_attempt_count( + self, async_client: AsyncOpenAI, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture + ) -> None: + client = async_client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < 2: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/chat/completions").mock(side_effect=retry_handler) + + with caplog.at_level(logging.INFO): + await client.chat.completions.with_raw_response.create( + messages=[ + { + "content": "string", + "role": "developer", + } + ], + model="gpt-5.4", + ) + + assert any("Retrying request to /chat/completions" in message and "(1/4)" in message for message in caplog.messages) + assert any("Retrying request to /chat/completions" in message and "(2/4)" in message for message in caplog.messages) + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url)