From d6abf990c71b524a91fbae8d319f085c68037eeb Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 21 May 2026 16:15:11 +0200 Subject: [PATCH] feat(ocr): flip ocr_models_ready to 1 once the lifespan startup finishes Mirrors the existing _models_ready bool so Prometheus has a time-series liveness/readiness signal for future alerting rules (e.g. ocr_models_ready < 1 for 2m). Refs #652 (AC7) Co-Authored-By: Claude Sonnet 4.6 --- ocr-service/main.py | 1 + ocr-service/test_metrics.py | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/ocr-service/main.py b/ocr-service/main.py index 1460a213..f7dc495d 100644 --- a/ocr-service/main.py +++ b/ocr-service/main.py @@ -69,6 +69,7 @@ async def lifespan(app: FastAPI): kraken_engine.load_models() load_spell_checker() _models_ready = True + metrics.ocr_models_ready.set(1) logger.info("Startup complete — ready to accept requests") yield diff --git a/ocr-service/test_metrics.py b/ocr-service/test_metrics.py index 7d154102..5c472dbe 100644 --- a/ocr-service/test_metrics.py +++ b/ocr-service/test_metrics.py @@ -422,3 +422,23 @@ async def test_ocr_model_accuracy_gauge_set_per_kind_after_successful_training(f assert fresh_metrics.ocr_model_accuracy.labels(kind="recognition")._value.get() == pytest.approx(recognition_accuracy) assert fresh_metrics.ocr_model_accuracy.labels(kind="segmentation")._value.get() == pytest.approx(segmentation_accuracy) + + +def test_ocr_models_ready_gauge_defaults_to_zero(): + """A freshly-built OcrMetrics has ocr_models_ready=0 before lifespan runs.""" + metrics = build_metrics(CollectorRegistry()) + assert metrics.ocr_models_ready._value.get() == 0.0 + + +@pytest.mark.asyncio +async def test_ocr_models_ready_gauge_is_one_after_lifespan_startup(fresh_metrics): + """The lifespan flips ocr_models_ready to 1 once load_models / load_spell_checker return. + + ASGITransport does not run lifespan by default, so the lifespan context + manager is driven directly to exercise the startup code path. + """ + assert fresh_metrics.ocr_models_ready._value.get() == 0.0 + with patch("main.kraken_engine.load_models"), \ + patch("main.load_spell_checker"): + async with app.router.lifespan_context(app): + assert fresh_metrics.ocr_models_ready._value.get() == 1.0