Retries, timeouts, hooks¶
RetryPolicy¶
Defaults retry HTTP {429, 502, 503, 504} (and gRPC
{UNAVAILABLE, DEADLINE_EXCEEDED, RESOURCE_EXHAUSTED}) up to 3 times with
exponential backoff + jitter. Retry-After is honoured.
RetryPolicy
dataclass
¶
RetryPolicy(attempts: int = 3, backoff: float = 0.25, backoff_cap: float = 8.0, jitter: float = 0.1, retry_statuses: frozenset[int] = DEFAULT_RETRY_STATUSES, retry_methods: frozenset[str] = (lambda: DEFAULT_RETRY_METHODS)(), retry_grpc_statuses: frozenset[str] = (lambda: DEFAULT_RETRY_GRPC_STATUSES)(), respect_retry_after: bool = True)
Exponential-backoff retry policy for transient HTTP/gRPC failures.
Each retry attempt waits min(backoff_cap, backoff * 2 ** (attempt - 1))
+ random.uniform(0, jitter) seconds before firing. When the server
sends a Retry-After header (HTTP) and respect_retry_after is True,
the effective delay is max(backoff, retry_after) — server hints
extend backoff but never shorten it.
Note: retries replay the whole request, including the body. The server
does not support range/resume uploads, so a 502 at the tail end of a
large PDF upload triggers a full re-upload on the next attempt. For
very large payloads over unstable links, keep attempts low and let
your own pipeline manage the retry budget.
| PARAMETER | DESCRIPTION |
|---|---|
attempts
|
Total request attempts before giving up.
TYPE:
|
backoff
|
Base delay in seconds for the first retry. Doubles each
subsequent attempt up to
TYPE:
|
backoff_cap
|
Maximum exponential delay (seconds) before jitter is added. Caps the geometric growth.
TYPE:
|
jitter
|
Upper bound (seconds) of uniform random jitter added to each delay. Prevents thundering-herd reconnects.
TYPE:
|
retry_statuses
|
HTTP status codes considered transient. Defaults
to
TYPE:
|
retry_methods
|
HTTP methods eligible for retry. Defaults to
TYPE:
|
retry_grpc_statuses
|
gRPC status names eligible for retry.
Defaults to
TYPE:
|
respect_retry_after
|
When
TYPE:
|
Example
| METHOD | DESCRIPTION |
|---|---|
should_retry_status |
|
should_retry_method |
|
should_retry_grpc_status_name |
|
delay_for |
|
delay_with_retry_after |
|
| ATTRIBUTE | DESCRIPTION |
|---|---|
attempts |
TYPE:
|
backoff |
TYPE:
|
backoff_cap |
TYPE:
|
jitter |
TYPE:
|
retry_statuses |
TYPE:
|
retry_methods |
TYPE:
|
retry_grpc_statuses |
TYPE:
|
respect_retry_after |
TYPE:
|
Timeouts¶
Two layers:
- Client-wide:
Client(timeout=30.0, ...)sets the per-request default. - Per-call:
client.recognize_image("page.png", timeout=15.0)overrides the default for that single call. A per-calltimeout=Nonemeans "no per-call override — use the client default".
For finer control, pass a pre-built httpx.Timeout via http_client=:
import httpx
from turboocr import Client
http = httpx.Client(
base_url="http://localhost:8000",
timeout=httpx.Timeout(connect=2.0, read=60.0, write=60.0, pool=30.0),
)
client = Client(http_client=http)
Hooks¶
on_request / on_response are httpx event hooks invoked around every
request. Use them for OpenTelemetry spans, request counters, or simple stdout
tracing.
import httpx
from turboocr import Client
def on_request(request: httpx.Request) -> None:
print(f"-> {request.method} {request.url.path}")
def on_response(response: httpx.Response) -> None:
print(f"<- {response.status_code} {response.request.url.path}")
client = Client(on_request=on_request, on_response=on_response)
See docs/12_hooks_and_logging.py for
a runnable version.