Skip to content

Commit f690991

Browse files
Handle malformed status codes in retry classification
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent beedfb9 commit f690991

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

hyperbrowser/client/polling.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ def _is_retryable_exception(exc: Exception) -> bool:
114114
if isinstance(exc, _NonRetryablePollingError):
115115
return False
116116
if isinstance(exc, HyperbrowserError) and exc.status_code is not None:
117+
if isinstance(exc.status_code, bool) or not isinstance(exc.status_code, int):
118+
return True
117119
if (
118120
_CLIENT_ERROR_STATUS_MIN <= exc.status_code < _CLIENT_ERROR_STATUS_MAX
119121
and exc.status_code not in _RETRYABLE_CLIENT_ERROR_STATUS_CODES

tests/test_polling.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,34 @@ async def get_status() -> str:
169169
asyncio.run(run())
170170

171171

172+
def test_poll_until_terminal_status_async_handles_non_integer_status_codes_as_retryable():
173+
async def run() -> None:
174+
attempts = {"count": 0}
175+
176+
async def get_status() -> str:
177+
attempts["count"] += 1
178+
if attempts["count"] < 3:
179+
raise HyperbrowserError(
180+
"malformed status code",
181+
status_code="400", # type: ignore[arg-type]
182+
)
183+
return "completed"
184+
185+
status = await poll_until_terminal_status_async(
186+
operation_name="async poll malformed status code retries",
187+
get_status=get_status,
188+
is_terminal_status=lambda value: value == "completed",
189+
poll_interval_seconds=0.0001,
190+
max_wait_seconds=1.0,
191+
max_status_failures=5,
192+
)
193+
194+
assert status == "completed"
195+
assert attempts["count"] == 3
196+
197+
asyncio.run(run())
198+
199+
172200
def test_poll_until_terminal_status_retries_server_errors():
173201
attempts = {"count": 0}
174202

@@ -337,6 +365,29 @@ def operation() -> str:
337365
assert attempts["count"] == 3
338366

339367

368+
def test_retry_operation_handles_non_integer_status_codes_as_retryable():
369+
attempts = {"count": 0}
370+
371+
def operation() -> str:
372+
attempts["count"] += 1
373+
if attempts["count"] < 3:
374+
raise HyperbrowserError(
375+
"malformed status code",
376+
status_code="400", # type: ignore[arg-type]
377+
)
378+
return "ok"
379+
380+
result = retry_operation(
381+
operation_name="sync retry malformed status code",
382+
operation=operation,
383+
max_attempts=5,
384+
retry_delay_seconds=0.0001,
385+
)
386+
387+
assert result == "ok"
388+
assert attempts["count"] == 3
389+
390+
340391
def test_retry_operation_rejects_awaitable_operation_result():
341392
async def async_operation() -> str:
342393
return "ok"

0 commit comments

Comments
 (0)