From 5b05c8fec677561b0635d8ba2db2afc80530c6f3 Mon Sep 17 00:00:00 2001 From: Stephen Zweibel Date: Thu, 27 Aug 2026 13:11:44 -0400 Subject: [PATCH] Retry transient Docling readiness connections --- backend/app/services/readiness.py | 9 ++++++++- backend/tests/test_readiness.py | 18 ++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/backend/app/services/readiness.py b/backend/app/services/readiness.py index addce04..f87be71 100644 --- a/backend/app/services/readiness.py +++ b/backend/app/services/readiness.py @@ -16,6 +16,7 @@ from app.services.runtime_paths import resolve_binary _DOCLING_HEALTH_TIMEOUT_SECONDS = 5.0 +_DOCLING_HEALTH_CONNECT_RETRIES = 2 def _check_payload( @@ -150,7 +151,13 @@ async def _docling_check(settings: Any, diagnostics: dict[str, Any]) -> dict[str headers = {"Authorization": f"Bearer {token}"} if token else {} try: timeout = httpx.Timeout(_DOCLING_HEALTH_TIMEOUT_SECONDS) - async with httpx.AsyncClient(timeout=timeout) as client: + transport = httpx.AsyncHTTPTransport( + retries=_DOCLING_HEALTH_CONNECT_RETRIES + ) + async with httpx.AsyncClient( + timeout=timeout, + transport=transport, + ) as client: response = await client.get(health_url, headers=headers) except httpx.ConnectError: return _check_payload( diff --git a/backend/tests/test_readiness.py b/backend/tests/test_readiness.py index 052b2b0..090591a 100644 --- a/backend/tests/test_readiness.py +++ b/backend/tests/test_readiness.py @@ -40,9 +40,14 @@ def _remote_docling_settings(tmp_path, *, token=""): def _patch_async_client(monkeypatch, *, response=None, error=None): calls = [] + class FakeTransport: + def __init__(self, *, retries): + self.retries = retries + class FakeAsyncClient: - def __init__(self, *, timeout): + def __init__(self, *, timeout, transport): self.timeout = timeout + self.transport = transport async def __aenter__(self): return self @@ -51,11 +56,19 @@ async def __aexit__(self, _exc_type, _exc_value, _traceback): return None async def get(self, url, *, headers): - calls.append({"timeout": self.timeout, "url": url, "headers": headers}) + calls.append( + { + "timeout": self.timeout, + "transport": self.transport, + "url": url, + "headers": headers, + } + ) if error is not None: raise error return response + monkeypatch.setattr(readiness.httpx, "AsyncHTTPTransport", FakeTransport) monkeypatch.setattr(readiness.httpx, "AsyncClient", FakeAsyncClient) return calls @@ -138,6 +151,7 @@ async def test_remote_docling_health_check_uses_canonical_endpoint_and_timeout( assert calls[0]["headers"] == {} assert calls[0]["timeout"].connect == 5 assert calls[0]["timeout"].read == 5 + assert calls[0]["transport"].retries == 2 @pytest.mark.asyncio