Probe docling-serve only when converter or chunker uses it
This commit is contained in:
parent
b0d0ac588d
commit
15d13cab04
2 changed files with 55 additions and 3 deletions
|
|
@ -29,9 +29,16 @@ async def _probe(client: httpx.AsyncClient, base_url: str) -> ProviderEndpoint:
|
||||||
|
|
||||||
@router.get("/providers", response_model=ProvidersResponse)
|
@router.get("/providers", response_model=ProvidersResponse)
|
||||||
async def providers(state: APIState = Depends(get_state)) -> ProvidersResponse:
|
async def providers(state: APIState = Depends(get_state)) -> ProvidersResponse:
|
||||||
"""Probe configured external providers (currently docling-serve) and
|
"""Probe external providers actually in use by the current converter /
|
||||||
return their reachability. Dashboard polls this to surface a downstream
|
chunker and return their reachability. Dashboard polls this to surface a
|
||||||
outage that the ingester itself can only see via worker job failures."""
|
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
|
base_urls = state.config.providers.docling_serve.base_urls
|
||||||
async with httpx.AsyncClient(timeout=_PROBE_TIMEOUT_S) as client:
|
async with httpx.AsyncClient(timeout=_PROBE_TIMEOUT_S) as client:
|
||||||
results = await asyncio.gather(*(_probe(client, u) for u in base_urls))
|
results = await asyncio.gather(*(_probe(client, u) for u in base_urls))
|
||||||
|
|
|
||||||
|
|
@ -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)
|
return ProviderEndpoint(base_url=base_url, reachable=True, status_code=200)
|
||||||
|
|
||||||
monkeypatch.setattr(providers_mod, "_probe", _fake_probe)
|
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 = [
|
state.config.providers.docling_serve.base_url = [
|
||||||
"http://docling-serve-up:5001",
|
"http://docling-serve-up:5001",
|
||||||
"http://docling-serve-down: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"]
|
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
|
@pytest.mark.asyncio
|
||||||
async def test_providers_probe_with_real_httpx_transport():
|
async def test_providers_probe_with_real_httpx_transport():
|
||||||
"""End-to-end through the actual _probe — MockTransport drives the
|
"""End-to-end through the actual _probe — MockTransport drives the
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue