Add historical UI and backend API slice
This commit is contained in:
160
backend/app/historical_runner.py
Normal file
160
backend/app/historical_runner.py
Normal file
@@ -0,0 +1,160 @@
|
||||
"""Local development loop for periodic historical CRCON refreshes."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import time
|
||||
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
|
||||
|
||||
|
||||
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 until interrupted or the limit is reached."""
|
||||
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:
|
||||
result = run_incremental_refresh(
|
||||
server_slug=server_slug,
|
||||
max_pages=max_pages,
|
||||
page_size=page_size,
|
||||
)
|
||||
return {
|
||||
"status": "ok",
|
||||
"attempts_used": attempt,
|
||||
"max_retries": max_retries,
|
||||
"result": 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 main() -> None:
|
||||
"""Allow local scheduled historical refresh execution without external infra."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Run periodic historical CRCON refreshes for HLL Vietnam.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--interval",
|
||||
type=int,
|
||||
default=get_historical_refresh_interval_seconds(),
|
||||
help="Seconds to wait between incremental refresh 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()
|
||||
Reference in New Issue
Block a user