Files
max2telegram/src/health_web.py
T
2026-04-09 12:35:45 +03:00

80 lines
2.7 KiB
Python

import json
import logging
import threading
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from typing import Any
from health import HealthState
logger = logging.getLogger(__name__)
class _Handler(BaseHTTPRequestHandler):
health: HealthState
def log_message(self, format: str, *args: Any) -> None: # noqa: A003
# Убираем спам от http.server, оставляем только наши логи.
logger.debug("health_http " + format, *args)
def _send_json(self, status: int, payload: dict[str, Any]) -> None:
body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
self.send_response(status)
self.send_header("Content-Type", "application/json; charset=utf-8")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def do_GET(self) -> None: # noqa: N802
if self.path in {"/livez", "/live", "/"}:
snap = self.health.snapshot()
self._send_json(
200,
{
"status": "live",
"uptime_sec": snap.uptime_sec,
},
)
return
if self.path in {"/healthz", "/health"}:
snap = self.health.snapshot()
status = 200 if snap.overall_healthy else 503
self._send_json(
status,
{
"status": "ok" if snap.overall_healthy else "unhealthy",
"telegram": {
"healthy": snap.telegram_healthy,
"last_ok_ago_sec": snap.telegram_last_ok_ago_sec,
"last_error_ago_sec": snap.telegram_last_error_ago_sec,
},
"max": {
"healthy": snap.max_healthy,
"last_ok_ago_sec": snap.max_last_ok_ago_sec,
"last_error_ago_sec": snap.max_last_error_ago_sec,
"last_event_ago_sec": snap.max_last_event_ago_sec,
},
"uptime_sec": snap.uptime_sec,
},
)
return
self._send_json(404, {"error": "not_found"})
def start_health_server(*, host: str, port: int, health: HealthState) -> threading.Thread:
class Handler(_Handler):
pass
Handler.health = health
server = ThreadingHTTPServer((host, port), Handler)
def _run() -> None:
logger.info("Health server listening on %s:%s", host, port)
server.serve_forever(poll_interval=0.5)
thread = threading.Thread(target=_run, name="health-http", daemon=True)
thread.start()
return thread