94 lines
3.0 KiB
Python
94 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
import argparse
|
|
import asyncio
|
|
import json
|
|
import logging
|
|
from dataclasses import dataclass
|
|
from typing import Any, Dict, Optional, Tuple
|
|
|
|
import aiohttp
|
|
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s")
|
|
log = logging.getLogger("health_check")
|
|
|
|
|
|
@dataclass
|
|
class HealthReport:
|
|
base_url: str
|
|
alive: bool
|
|
ready: bool
|
|
health_status: int
|
|
info_status: int
|
|
metrics_status: int
|
|
details: Dict[str, Any]
|
|
|
|
|
|
async def fetch_json(session: aiohttp.ClientSession, url: str) -> Tuple[int, Dict[str, Any]]:
|
|
try:
|
|
async with session.get(url) as resp:
|
|
status = resp.status
|
|
try:
|
|
data = await resp.json(content_type=None)
|
|
except Exception:
|
|
text = await resp.text()
|
|
data = {"raw": text}
|
|
return status, data
|
|
except Exception as e:
|
|
return 0, {"error": str(e)}
|
|
|
|
|
|
async def probe(base_url: str, timeout: int = 8) -> HealthReport:
|
|
timeout_cfg = aiohttp.ClientTimeout(total=timeout)
|
|
async with aiohttp.ClientSession(timeout=timeout_cfg) as session:
|
|
details: Dict[str, Any] = {}
|
|
|
|
async def _g(path: str):
|
|
url = f"{base_url.rstrip('/')}{path}"
|
|
s, d = await fetch_json(session, url)
|
|
details[path] = {"status": s, "data": d}
|
|
return s, d
|
|
|
|
health_s, _ = await _g("/api/system/health")
|
|
info_s, _ = await _g("/api/system/info")
|
|
metrics_s, _ = await _g("/api/system/metrics")
|
|
live_s, _ = await _g("/api/system/live")
|
|
ready_s, _ = await _g("/api/system/ready")
|
|
|
|
alive = live_s in (200, 204)
|
|
ready = ready_s in (200, 204)
|
|
|
|
return HealthReport(
|
|
base_url=base_url,
|
|
alive=alive,
|
|
ready=ready,
|
|
health_status=health_s,
|
|
info_status=info_s,
|
|
metrics_status=metrics_s,
|
|
details=details,
|
|
)
|
|
|
|
|
|
def main() -> int:
|
|
ap = argparse.ArgumentParser(description="Проверка здоровья системы (health/info/metrics/ready/live)")
|
|
ap.add_argument("base_url", help="Базовый URL FastAPI, например http://localhost:8000")
|
|
ap.add_argument("-t", "--timeout", type=int, default=8)
|
|
ap.add_argument("--json", action="store_true", help="Вывод в JSON")
|
|
args = ap.parse_args()
|
|
|
|
report = asyncio.run(probe(args.base_url, timeout=args.timeout))
|
|
|
|
if args.json:
|
|
print(json.dumps(report.__dict__, ensure_ascii=False, indent=2))
|
|
else:
|
|
print(f"Health check for {report.base_url}")
|
|
print(f"- alive={report.alive} ready={report.ready}")
|
|
print(f"- /api/system/health: {report.health_status}")
|
|
print(f"- /api/system/info: {report.info_status}")
|
|
print(f"- /api/system/metrics: {report.metrics_status}")
|
|
|
|
# Код возврата: 0 если живой и готов, иначе 2
|
|
return 0 if (report.alive and report.ready) else 2
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main()) |