운영 지표와 지원 요청 저장소 추가
This commit is contained in:
parent
50fa4ad432
commit
e7ebb38177
20 changed files with 3038 additions and 39 deletions
98
scripts/maintain-admin-health-events.py
Normal file
98
scripts/maintain-admin-health-events.py
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Roll up and optionally prune persisted admin health samples."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from dataclasses import asdict
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
API_ROOT = REPO_ROOT / "apps" / "api"
|
||||
|
||||
if hasattr(sys.stdout, "reconfigure"):
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
if hasattr(sys.stderr, "reconfigure"):
|
||||
sys.stderr.reconfigure(encoding="utf-8")
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(
|
||||
description=(
|
||||
"Roll up app.admin_health_event into app.admin_health_daily_rollup "
|
||||
"and optionally prune old raw samples."
|
||||
)
|
||||
)
|
||||
parser.add_argument("--rollup-days", type=int, required=True, help="Roll up raw samples older than this many days.")
|
||||
parser.add_argument("--retention-days", type=int, required=True, help="Prune raw samples older than this many days.")
|
||||
parser.add_argument("--apply", action="store_true", help="Mutate the database. Default is dry-run.")
|
||||
parser.add_argument(
|
||||
"--allow-non-dev-apply",
|
||||
action="store_true",
|
||||
help="Required with --apply outside ENVIRONMENT=dev.",
|
||||
)
|
||||
parser.add_argument("--json", action="store_true", help="Print compact JSON.")
|
||||
return parser
|
||||
|
||||
|
||||
def _prepare_imports() -> None:
|
||||
os.chdir(API_ROOT)
|
||||
api_root = str(API_ROOT)
|
||||
if api_root not in sys.path:
|
||||
sys.path.insert(0, api_root)
|
||||
|
||||
|
||||
async def _run(args: argparse.Namespace) -> dict[str, object]:
|
||||
_prepare_imports()
|
||||
from app.auth_sessions import ensure_runtime_tables
|
||||
from app.config import settings
|
||||
from app.db import close_pool, init_pool
|
||||
from app.services.admin_health_maintenance import maintain_admin_health_events
|
||||
|
||||
if args.apply and settings.environment != "dev" and not args.allow_non_dev_apply:
|
||||
raise RuntimeError("--apply outside ENVIRONMENT=dev requires --allow-non-dev-apply")
|
||||
|
||||
await init_pool()
|
||||
try:
|
||||
await ensure_runtime_tables()
|
||||
result = await maintain_admin_health_events(
|
||||
rollup_days=args.rollup_days,
|
||||
retention_days=args.retention_days,
|
||||
apply=args.apply,
|
||||
)
|
||||
finally:
|
||||
await close_pool()
|
||||
return asdict(result)
|
||||
|
||||
|
||||
def _print_result(result: dict[str, object], *, as_json: bool) -> None:
|
||||
if as_json:
|
||||
print(json.dumps(result, ensure_ascii=False, separators=(",", ":")))
|
||||
return
|
||||
mode = "applied" if result["applied"] else "dry-run"
|
||||
print(
|
||||
"{mode}: rollup_events={rollup_event_count}, rollup_buckets={rollup_bucket_count}, "
|
||||
"upserted_rollups={upserted_rollups}, prunable_events={prunable_event_count}, "
|
||||
"deleted_events={deleted_events}".format(mode=mode, **result)
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = build_parser().parse_args()
|
||||
try:
|
||||
result = asyncio.run(_run(args))
|
||||
except Exception as exc: # noqa: BLE001 - CLI should report compact failure.
|
||||
payload = {"ok": False, "error_type": exc.__class__.__name__, "error": str(exc)}
|
||||
print(json.dumps(payload, ensure_ascii=False, separators=(",", ":")), file=sys.stderr)
|
||||
return 2
|
||||
_print_result(result, as_json=args.json)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Loading…
Add table
Add a link
Reference in a new issue