"""Local development loop for periodic historical CRCON refreshes.""" from __future__ import annotations import argparse import json import time from datetime import datetime, timezone from typing import Any from .config import ( get_historical_refresh_interval_seconds, get_historical_refresh_max_retries, get_historical_refresh_retry_delay_seconds, ) from .historical_ingestion import run_incremental_refresh from .historical_snapshots import generate_and_persist_historical_snapshots def run_periodic_historical_refresh( *, interval_seconds: int, max_retries: int, retry_delay_seconds: int, server_slug: str | None = None, max_pages: int | None = None, page_size: int | None = None, max_runs: int | None = None, ) -> None: """Run periodic historical refreshes and rebuild persisted snapshots.""" completed_runs = 0 print( "Starting historical refresh loop " f"(interval={interval_seconds}s, retries={max_retries}, server={server_slug or 'all'})." ) print("Press Ctrl+C to stop.") try: while max_runs is None or completed_runs < max_runs: completed_runs += 1 payload = _run_refresh_with_retries( max_retries=max_retries, retry_delay_seconds=retry_delay_seconds, server_slug=server_slug, max_pages=max_pages, page_size=page_size, ) print(json.dumps({"run": completed_runs, **payload}, indent=2)) if max_runs is not None and completed_runs >= max_runs: break time.sleep(interval_seconds) except KeyboardInterrupt: print("\nHistorical refresh loop stopped by user.") def _run_refresh_with_retries( *, max_retries: int, retry_delay_seconds: int, server_slug: str | None, max_pages: int | None, page_size: int | None, ) -> dict[str, Any]: attempt = 0 while True: attempt += 1 try: refresh_result = run_incremental_refresh( server_slug=server_slug, max_pages=max_pages, page_size=page_size, ) snapshot_result = generate_historical_snapshots(server_slug=server_slug) return { "status": "ok", "attempts_used": attempt, "max_retries": max_retries, "refresh_result": refresh_result, "snapshot_result": snapshot_result, } except Exception as exc: if attempt > max_retries: return { "status": "error", "attempts_used": attempt, "max_retries": max_retries, "error": str(exc), } if retry_delay_seconds > 0: time.sleep(retry_delay_seconds) def generate_historical_snapshots( *, server_slug: str | None = None, ) -> dict[str, Any]: """Build and persist precomputed snapshots for one server or all servers.""" result = generate_and_persist_historical_snapshots( server_key=server_slug, generated_at=datetime.now(timezone.utc), ) return { **result, "refresh_interval_seconds": get_historical_refresh_interval_seconds(), } def main() -> None: """Allow local scheduled historical refresh execution without external infra.""" parser = argparse.ArgumentParser( description="Run periodic historical refreshes and regenerate snapshots for HLL Vietnam.", ) parser.add_argument( "--interval", type=int, default=get_historical_refresh_interval_seconds(), help="Seconds to wait between refresh-plus-snapshot runs.", ) parser.add_argument( "--retries", type=int, default=get_historical_refresh_max_retries(), help="Retry attempts after a failed incremental refresh.", ) parser.add_argument( "--retry-delay", type=int, default=get_historical_refresh_retry_delay_seconds(), help="Seconds to wait between failed attempts.", ) parser.add_argument( "--server", dest="server_slug", help="Optional historical server slug.", ) parser.add_argument( "--max-pages", type=int, default=None, help="Optional page cap for local validation.", ) parser.add_argument( "--page-size", type=int, default=None, help="Optional override for CRCON page size.", ) parser.add_argument( "--max-runs", type=int, default=None, help="Optional safety limit for the number of refresh cycles to execute.", ) args = parser.parse_args() if args.interval <= 0: raise ValueError("--interval must be a positive integer.") if args.retries < 0: raise ValueError("--retries must be zero or positive.") if args.retry_delay < 0: raise ValueError("--retry-delay must be zero or positive.") if args.max_runs is not None and args.max_runs <= 0: raise ValueError("--max-runs must be positive when provided.") run_periodic_historical_refresh( interval_seconds=args.interval, max_retries=args.retries, retry_delay_seconds=args.retry_delay, server_slug=args.server_slug, max_pages=args.max_pages, page_size=args.page_size, max_runs=args.max_runs, ) if __name__ == "__main__": main()