diff --git a/apps/api/app/readiness.py b/apps/api/app/readiness.py index fe85fec..1340ceb 100644 --- a/apps/api/app/readiness.py +++ b/apps/api/app/readiness.py @@ -78,7 +78,9 @@ def readiness_report( "status": "ready" if healthy else ("stale" if stale else latest_community.status), "last_started_at": started.isoformat(), } + ready = ready and healthy except Exception: components["community_scheduler"] = {"status": "unknown"} + ready = False return ready, components diff --git a/apps/api/tests/test_readiness.py b/apps/api/tests/test_readiness.py index 2187622..4dcc1de 100644 --- a/apps/api/tests/test_readiness.py +++ b/apps/api/tests/test_readiness.py @@ -6,7 +6,7 @@ from sqlalchemy import create_engine from sqlalchemy.orm import Session from app.database import Base -from app.models import ImportStatus, OfficialRecordImport +from app.models import ImportStatus, CommunityImportRun, OfficialRecordImport from app.readiness import readiness_report @@ -72,3 +72,68 @@ def test_unavailable_storage_and_stale_import_fail_readiness() -> None: assert ready is False assert components["minio"]["status"] == "unavailable" assert components["official_import"]["status"] == "stale" + + +def test_community_scheduler_success_does_not_block_readiness() -> None: + engine = create_engine("sqlite://") + Base.metadata.create_all(engine) + now = datetime.now(timezone.utc) + with Session(engine) as session: + session.add(CommunityImportRun( + source_system="rf4db", + started_at=now - timedelta(minutes=30), + status="success", + source_url="fixture://rf4db", + rows_seen=5, rows_created=5, rows_updated=0, error_summary=None, + )) + session.commit() + ready, components = readiness_report( + session, AvailableStorage(), import_required=False, + import_interval_seconds=3600, community_import_interval_seconds=1800, now=now, + ) + assert ready is True + assert components["community_scheduler"]["status"] == "ready" + + +def test_community_scheduler_stale_or_failed_blocks_readiness() -> None: + engine = create_engine("sqlite://") + Base.metadata.create_all(engine) + now = datetime.now(timezone.utc) + with Session(engine) as session: + # Stale run + session.add(CommunityImportRun( + source_system="rf4db", + started_at=now - timedelta(hours=2), + status="success", + source_url="fixture://rf4db", + rows_seen=5, rows_created=5, rows_updated=0, error_summary=None, + )) + session.commit() + ready, components = readiness_report( + session, AvailableStorage(), import_required=False, + import_interval_seconds=3600, community_import_interval_seconds=1800, now=now, + ) + assert ready is False + assert components["community_scheduler"]["status"] == "stale" + + +def test_community_scheduler_failed_status_blocks_readiness() -> None: + engine = create_engine("sqlite://") + Base.metadata.create_all(engine) + now = datetime.now(timezone.utc) + with Session(engine) as session: + session.add(CommunityImportRun( + source_system="rf4db", + started_at=now - timedelta(minutes=30), + status="failed", + source_url="fixture://rf4db", + rows_seen=0, rows_created=0, rows_updated=0, + error_summary="ConnectionError", + )) + session.commit() + ready, components = readiness_report( + session, AvailableStorage(), import_required=False, + import_interval_seconds=3600, community_import_interval_seconds=1800, now=now, + ) + assert ready is False + assert components["community_scheduler"]["status"] == "failed"