mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-09-23 18:00:32 +00:00
util_call_with_backoff made every call wait 20 seconds even when the first attempt succeeded The helper now sleeps only after a failure that has another attempt left.
77 lines
2.2 KiB
Python
77 lines
2.2 KiB
Python
from __future__ import annotations
|
|
|
|
import time
|
|
import warnings
|
|
from typing import TYPE_CHECKING
|
|
from typing import Any
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
from documents.parsers import ParseError
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Callable
|
|
|
|
|
|
def util_call_with_backoff(
|
|
method_or_callable: Callable,
|
|
args: list | tuple,
|
|
*,
|
|
skip_on_50x_err: bool = True,
|
|
) -> tuple[bool, Any]:
|
|
"""
|
|
For whatever reason, the images started during the test pipeline like to
|
|
segfault sometimes, crash and otherwise fail randomly, when run with the
|
|
exact files that usually pass.
|
|
|
|
So, this function will retry the given method/function up to 3 times, with larger backoff
|
|
periods between each attempt, in hopes the issue resolves itself during
|
|
one attempt to parse.
|
|
|
|
This will wait the following:
|
|
- Attempt 1 - 20s following failure
|
|
- Attempt 2 - 40s following failure
|
|
- Attempt 3 - 80s following failure
|
|
|
|
"""
|
|
result = None
|
|
succeeded = False
|
|
retry_time = 20.0
|
|
retry_count = 0
|
|
status_codes = []
|
|
max_retry_count = 3
|
|
|
|
while retry_count < max_retry_count and not succeeded:
|
|
try:
|
|
result = method_or_callable(*args)
|
|
|
|
succeeded = True
|
|
except ParseError as e: # pragma: no cover
|
|
cause_exec = e.__cause__
|
|
if cause_exec is not None and isinstance(cause_exec, httpx.HTTPStatusError):
|
|
status_codes.append(cause_exec.response.status_code)
|
|
warnings.warn(
|
|
f"HTTP Exception for {cause_exec.request.url} - {cause_exec}",
|
|
)
|
|
else:
|
|
warnings.warn(f"Unexpected error: {e}")
|
|
except Exception as e: # pragma: no cover
|
|
warnings.warn(f"Unexpected error: {e}")
|
|
|
|
retry_count = retry_count + 1
|
|
|
|
if not succeeded and retry_count < max_retry_count:
|
|
time.sleep(retry_time)
|
|
retry_time = retry_time * 2.0
|
|
|
|
if (
|
|
not succeeded
|
|
and status_codes
|
|
and skip_on_50x_err
|
|
and all(httpx.codes.is_server_error(code) for code in status_codes)
|
|
):
|
|
pytest.skip("Repeated HTTP 50x for service") # pragma: no cover
|
|
|
|
return succeeded, result
|