feat: host heartbeat status and dashboard metrics (2.2)

Track agent.heartbeat and report.daily.ssh per host; show online/stale
on Hosts UI; dashboard counters and SAC_HEARTBEAT_STALE_MINUTES config.
This commit is contained in:
PTah
2026-05-27 13:36:17 +10:00
parent 9ba3c4b63b
commit 04301ab359
14 changed files with 246 additions and 4 deletions
+16
View File
@@ -10,6 +10,8 @@ from sqlalchemy.orm import Session
from app.auth.jwt_auth import verify_access_token
from app.database import SessionLocal
from app.models import Event, Problem
from app.config import get_settings
from app.services.host_health import DAILY_REPORT_SSH, HEARTBEAT_TYPE, count_stale_hosts
from app.version import APP_VERSION
router = APIRouter(prefix="/stream", tags=["stream"])
@@ -26,10 +28,24 @@ def _dashboard_snapshot(db: Session) -> dict:
db.scalar(select(func.count()).select_from(Problem).where(Problem.status == "open")) or 0
)
last_event = db.scalar(select(Event.id).order_by(Event.received_at.desc()).limit(1))
settings = get_settings()
return {
"type": "dashboard",
"version": APP_VERSION,
"events_last_24h": events_24h,
"hosts_stale": count_stale_hosts(db, settings.sac_heartbeat_stale_minutes),
"heartbeats_24h": db.scalar(
select(func.count())
.select_from(Event)
.where(Event.received_at >= since, Event.type == HEARTBEAT_TYPE)
)
or 0,
"daily_reports_24h": db.scalar(
select(func.count())
.select_from(Event)
.where(Event.received_at >= since, Event.type == DAILY_REPORT_SSH)
)
or 0,
"problems_open": problems_open,
"last_event_id": last_event,
"at": datetime.now(timezone.utc).isoformat(),