后台新增 API 状态检测页:实时检测 Supabase/Open-Meteo/METAR/KNMI/MADIS/Telegram 连通性

This commit is contained in:
2569718930@qq.com
2026-05-18 23:25:16 +08:00
parent 5b1402fc7c
commit c38dc80f58
11 changed files with 259 additions and 9 deletions
+6
View File
@@ -7,6 +7,7 @@ from web.services.ops_api import (
extend_ops_subscription,
get_ops_analytics_funnel,
get_ops_config,
get_ops_health_check,
get_ops_logs,
get_ops_truth_history,
get_ops_weekly_leaderboard,
@@ -136,3 +137,8 @@ async def ops_logs(
lines: int = 100,
):
return get_ops_logs(request, level=level, lines=lines)
@router.get("/api/ops/health-check")
async def ops_health_check(request: Request):
return get_ops_health_check(request)
+71
View File
@@ -433,3 +433,74 @@ def get_ops_logs(
"lines": log_lines[-safe_lines:],
"total": len(log_lines),
}
def get_ops_health_check(request: Request) -> dict[str, Any]:
_require_ops(request)
import os, requests as _r, time as _time
results: dict[str, dict] = {}
timeout = 3
# Supabase
supabase_url = str(os.getenv("SUPABASE_URL") or "").strip().rstrip("/")
supabase_key = str(os.getenv("SUPABASE_SERVICE_ROLE_KEY") or "").strip()
if supabase_url and supabase_key:
try:
r = _r.get(f"{supabase_url}/rest/v1/", headers={"apikey": supabase_key, "Authorization": f"Bearer {supabase_key}"}, timeout=timeout)
results["supabase"] = {"ok": r.ok, "status": r.status_code, "latency_ms": round(r.elapsed.total_seconds() * 1000)}
except Exception as e:
results["supabase"] = {"ok": False, "error": str(e)[:100]}
else:
results["supabase"] = {"ok": False, "error": "not configured"}
# Open-Meteo
try:
t0 = _time.perf_counter()
r = _r.get("https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&daily=temperature_2m_max&timezone=auto&forecast_days=1", timeout=timeout)
results["open_meteo"] = {"ok": r.ok, "status": r.status_code, "latency_ms": round((_time.perf_counter() - t0) * 1000)}
except Exception as e:
results["open_meteo"] = {"ok": False, "error": str(e)[:100]}
# METAR (aviationweather)
try:
t0 = _time.perf_counter()
r = _r.get("https://aviationweather.gov/api/data/metar?ids=KJFK&format=json", timeout=timeout)
results["metar"] = {"ok": r.ok, "status": r.status_code, "latency_ms": round((_time.perf_counter() - t0) * 1000)}
except Exception as e:
results["metar"] = {"ok": False, "error": str(e)[:100]}
# KNMI
knmi_key = str(os.getenv("KNMI_API_KEY") or "").strip()
if knmi_key:
try:
t0 = _time.perf_counter()
r = _r.get("https://api.dataplatform.knmi.nl/open-data/v1/datasets", headers={"Authorization": knmi_key}, timeout=timeout)
results["knmi"] = {"ok": r.ok, "status": r.status_code, "latency_ms": round((_time.perf_counter() - t0) * 1000)}
except Exception as e:
results["knmi"] = {"ok": False, "error": str(e)[:100]}
else:
results["knmi"] = {"ok": False, "error": "not configured"}
# MADIS (NOAA)
try:
t0 = _time.perf_counter()
r = _r.get("https://madis-data.ncep.noaa.gov/madisPublic1/data/LDAD/hfmetar/netCDF/", timeout=timeout)
results["madis"] = {"ok": r.ok, "status": r.status_code, "latency_ms": round((_time.perf_counter() - t0) * 1000)}
except Exception as e:
results["madis"] = {"ok": False, "error": str(e)[:100]}
# Telegram Bot
bot_token = str(os.getenv("TELEGRAM_BOT_TOKEN") or "").strip()
if bot_token:
try:
t0 = _time.perf_counter()
r = _r.get(f"https://api.telegram.org/bot{bot_token}/getMe", timeout=timeout)
results["telegram"] = {"ok": r.ok, "status": r.status_code, "latency_ms": round((_time.perf_counter() - t0) * 1000)}
except Exception as e:
results["telegram"] = {"ok": False, "error": str(e)[:100]}
else:
results["telegram"] = {"ok": False, "error": "not configured"}
all_ok = all(v.get("ok") for v in results.values())
return {"ok": all_ok, "checked_at": __import__("datetime").datetime.utcnow().isoformat() + "Z", "services": results}