Probe docling-serve only when converter or chunker uses it

This commit is contained in:
Yiorgis Gozadinos 2026-05-27 15:18:25 +03:00
parent b0d0ac588d
commit 15d13cab04
No known key found for this signature in database
2 changed files with 55 additions and 3 deletions

View file

@ -29,9 +29,16 @@ async def _probe(client: httpx.AsyncClient, base_url: str) -> ProviderEndpoint:
@router.get("/providers", response_model=ProvidersResponse)
async def providers(state: APIState = Depends(get_state)) -> ProvidersResponse:
"""Probe configured external providers (currently docling-serve) and
return their reachability. Dashboard polls this to surface a downstream
outage that the ingester itself can only see via worker job failures."""
"""Probe external providers actually in use by the current converter /
chunker and return their reachability. Dashboard polls this to surface a
downstream outage that the ingester itself can only see via worker job
failures."""
processing = state.config.processing
uses_docling_serve = (
processing.converter == "docling-serve" or processing.chunker == "docling-serve"
)
if not uses_docling_serve:
return ProvidersResponse(docling_serve=[])
base_urls = state.config.providers.docling_serve.base_urls
async with httpx.AsyncClient(timeout=_PROBE_TIMEOUT_S) as client:
results = await asyncio.gather(*(_probe(client, u) for u in base_urls))

View file

@ -538,6 +538,8 @@ async def test_providers_probes_each_docling_serve_url(state, monkeypatch):
return ProviderEndpoint(base_url=base_url, reachable=True, status_code=200)
monkeypatch.setattr(providers_mod, "_probe", _fake_probe)
state.config.processing.converter = "docling-serve"
state.config.processing.chunker = "docling-serve"
state.config.providers.docling_serve.base_url = [
"http://docling-serve-up:5001",
"http://docling-serve-down:5001",
@ -556,6 +558,49 @@ async def test_providers_probes_each_docling_serve_url(state, monkeypatch):
assert "Name or service not known" in body["docling_serve"][1]["error"]
@pytest.mark.asyncio
async def test_providers_skips_docling_serve_when_not_in_use(state, monkeypatch):
"""With docling-local for both converter and chunker, /providers
returns an empty docling_serve list and crucially does not probe."""
from haiku.rag.ingester.api.routes import providers as providers_mod
probed: list[str] = []
async def _spy_probe(client, base_url): # pragma: no cover - asserted not called
probed.append(base_url)
raise AssertionError("probe should not run when docling-serve is not in use")
monkeypatch.setattr(providers_mod, "_probe", _spy_probe)
state.config.processing.converter = "docling-local"
state.config.processing.chunker = "docling-local"
async with _client(state) as client:
resp = await client.get("/providers")
assert resp.status_code == 200
assert resp.json() == {"docling_serve": []}
assert probed == []
@pytest.mark.asyncio
async def test_providers_probes_when_only_chunker_uses_docling_serve(
state, monkeypatch
):
"""A mixed config (local converter + docling-serve chunker, or vice versa)
still counts as 'in use' and triggers the probe."""
from haiku.rag.ingester.api.routes import providers as providers_mod
from haiku.rag.ingester.api.schemas import ProviderEndpoint
async def _fake_probe(client, base_url):
return ProviderEndpoint(base_url=base_url, reachable=True, status_code=200)
monkeypatch.setattr(providers_mod, "_probe", _fake_probe)
state.config.processing.converter = "docling-local"
state.config.processing.chunker = "docling-serve"
async with _client(state) as client:
resp = await client.get("/providers")
assert resp.status_code == 200
assert len(resp.json()["docling_serve"]) == 1
@pytest.mark.asyncio
async def test_providers_probe_with_real_httpx_transport():
"""End-to-end through the actual _probe — MockTransport drives the