|
# retoor <retoor@molodetz.nl>
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import time
|
|
|
|
from fastapi import APIRouter
|
|
|
|
from devplacepy_services.base.config import service_url
|
|
from devplacepy_services.base.http import internal_request
|
|
from devplacepy_services.base.schemas import HealthOut, HealthStatsOut
|
|
from devplacepy_services.base.service import BaseMicroservice
|
|
from devplacepy_services.base.stats import COUNTERS
|
|
|
|
|
|
async def _dep_status(name: str) -> str:
|
|
url = f"{service_url(name)}/health"
|
|
try:
|
|
response = await internal_request("GET", url, timeout=2.0)
|
|
if response.status_code == 200:
|
|
payload = response.json()
|
|
if payload.get("status") == "ok":
|
|
return "ok"
|
|
return "degraded"
|
|
return "down"
|
|
except Exception:
|
|
return "down"
|
|
|
|
|
|
def health_router(service: BaseMicroservice) -> APIRouter:
|
|
router = APIRouter()
|
|
|
|
@router.get("/health", response_model=HealthOut)
|
|
async def health() -> HealthOut:
|
|
deps: dict[str, str] = {}
|
|
if service.depends_on:
|
|
results = await asyncio.gather(
|
|
*[_dep_status(dep) for dep in service.depends_on]
|
|
)
|
|
for dep_name, status in zip(service.depends_on, results, strict=True):
|
|
deps[dep_name] = status
|
|
overall = "ok"
|
|
if deps and any(status != "ok" for status in deps.values()):
|
|
overall = "degraded"
|
|
uptime_s = int(time.monotonic() - service.started_at)
|
|
stats = COUNTERS.snapshot()
|
|
return HealthOut(
|
|
service=service.name,
|
|
status=overall,
|
|
uptime_s=uptime_s,
|
|
version=service.version,
|
|
deps=deps,
|
|
stats=HealthStatsOut(requests=stats["requests"], errors=stats["errors"]),
|
|
)
|
|
|
|
return router |