Files
call-center/scripts/track8_check.py
T

105 lines
3.6 KiB
Python

from __future__ import annotations
import argparse
import os
import sys
from datetime import datetime, timedelta, timezone
from pathlib import Path
from sqlalchemy import create_engine, inspect, select
from sqlalchemy.orm import Session
ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from scripts.event_bus_smoke import run_smoke_check
from services.shared.db import DATABASE_URL, _normalize_database_url
from services.shared.sql_models import EventOutboxRow
def _engine_for(database_url: str | None):
return create_engine(_normalize_database_url(database_url or DATABASE_URL), future=True)
def _parse_iso(value: str | None) -> datetime | None:
if not value:
return None
try:
return datetime.fromisoformat(value.replace("Z", "+00:00"))
except ValueError:
return None
def evaluate_track8(
*,
database_url: str | None = None,
require_bus_enabled: bool = False,
base_url: str | None = None,
failed_age_seconds: int = 300,
) -> list[str]:
issues: list[str] = []
engine = _engine_for(database_url)
inspector = inspect(engine)
tables = set(inspector.get_table_names())
required_tables = {"event_outbox", "event_inbox", "reporting_event_log"}
missing = sorted(required_tables - tables)
if missing:
issues.append(f"Missing required tables: {', '.join(missing)}")
if require_bus_enabled and os.getenv("EVENT_BUS_ENABLED", "0").strip() not in {"1", "true", "yes", "on"}:
issues.append("EVENT_BUS_ENABLED is not enabled in the current environment")
with Session(engine) as session:
failed_rows = session.execute(
select(EventOutboxRow).where(EventOutboxRow.status == "failed")
).scalars().all()
stale_cutoff = datetime.now(timezone.utc) - timedelta(seconds=failed_age_seconds)
stale_failed = [
row for row in failed_rows if (_parse_iso(row.updated_at) or _parse_iso(row.created_at) or stale_cutoff) < stale_cutoff
]
if stale_failed:
issues.append(f"Found {len(stale_failed)} failed outbox events older than {failed_age_seconds}s")
pending_rows = session.execute(
select(EventOutboxRow).where(EventOutboxRow.status == "pending")
).scalars().all()
if len(pending_rows) > 500:
issues.append(f"Outbox backlog too high: {len(pending_rows)} pending events")
if not (ROOT / "contracts" / "events" / "ivr.completed.json").exists():
issues.append("Missing contracts/events/ivr.completed.json")
if base_url:
smoke = run_smoke_check(base_url=base_url, database_url=database_url)
if not smoke["passed"]:
issues.append("Event bus smoke check failed")
return issues
def main() -> None:
parser = argparse.ArgumentParser(description="Validate Track 8 event-bus readiness.")
parser.add_argument("--database-url", default=None)
parser.add_argument("--require-bus-enabled", action="store_true")
parser.add_argument("--base-url", default=None)
parser.add_argument("--failed-age-seconds", type=int, default=300)
args = parser.parse_args()
issues = evaluate_track8(
database_url=args.database_url,
require_bus_enabled=args.require_bus_enabled,
base_url=args.base_url,
failed_age_seconds=args.failed_age_seconds,
)
if issues:
print("[FAIL] Track 8 validation failed:")
for issue in issues:
print(f"- {issue}")
raise SystemExit(1)
print("[PASS] Track 8 validation checks passed")
if __name__ == "__main__":
main()