feat(monitor): active push loop replacing standalone monitor
Adds a periodic POST loop to <backend>/monitor/server/heartbeat so HF plugin can take over the standalone harborforge-monitor daemon's job — same X-API-Key header, same flat telemetry shape (cpu_pct / mem_pct / disk_pct / swap_pct / load_avg / uptime_seconds / plugin_version / agents[]). HF backend stays unchanged. Config: monitor_push_enabled (default false; opt-in to avoid surprise heartbeats from existing deployments), monitor_push_interval_seconds (default 30), reuses apiKey for the X-API-Key header. Lift the container's HF_MONITER_API_KEY into config.apiKey, flip monitor_push_enabled true, then docker rm -f the container — DB last_seen_at keeps advancing under the plugin's loop. Collector grew swap + cpu sampling (two reads of /proc/stat over a 1-second window when SampleCPU=true). Bridge endpoint stays cheap (SampleCPU=false on demand); push loop is the only caller paying the sampling cost. E2E in sim: monitor_push_enabled=true + apiKey from injected MonitoredServer row → server_states.last_seen_at advances exactly every interval_seconds (10s configured, 10s observed). cpu/mem/disk/ swap_pct all populate correctly.
This commit is contained in:
@@ -27,6 +27,7 @@ type Deps struct {
|
||||
Version string
|
||||
Collect func() telemetry.Snapshot
|
||||
Bridge *monitor.Bridge
|
||||
Pusher *monitor.Pusher
|
||||
Scheduler *calendar.Scheduler
|
||||
Host sdkplugin.HostAPI
|
||||
|
||||
@@ -89,11 +90,32 @@ func toolStatus(deps Deps) (sdkplugin.ToolResult, error) {
|
||||
"queries": bs.Queries,
|
||||
"last_query": bs.LastQuery,
|
||||
},
|
||||
"calendar": sch,
|
||||
"monitor_push": monitorPushSummary(deps),
|
||||
"calendar": sch,
|
||||
}
|
||||
return jsonResult(out)
|
||||
}
|
||||
|
||||
// monitorPushSummary returns the pusher's last-known state in the same
|
||||
// JSON layout the status/monitor_telemetry tools surface. Nil-safe: if
|
||||
// no pusher is wired (testing, push disabled), reports enabled=false.
|
||||
func monitorPushSummary(deps Deps) map[string]any {
|
||||
out := map[string]any{
|
||||
"enabled": deps.Config.MonitorPushEnabled,
|
||||
"interval_seconds": deps.Config.MonitorPushIntervalSeconds,
|
||||
"endpoint": deps.Config.BackendURL + "/monitor/server/heartbeat",
|
||||
}
|
||||
if deps.Pusher != nil {
|
||||
st := deps.Pusher.Stats()
|
||||
out["last_sent_at"] = st.LastSentAt
|
||||
out["last_status"] = st.LastStatus
|
||||
out["last_err"] = st.LastErr
|
||||
out["success_count"] = st.SuccessCount
|
||||
out["error_count"] = st.ErrorCount
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func toolTelemetry(deps Deps) (sdkplugin.ToolResult, error) {
|
||||
return jsonResult(deps.Collect())
|
||||
}
|
||||
@@ -101,11 +123,14 @@ func toolTelemetry(deps Deps) (sdkplugin.ToolResult, error) {
|
||||
func toolMonitorTelemetry(deps Deps) (sdkplugin.ToolResult, error) {
|
||||
bs := deps.Bridge.Stats()
|
||||
return jsonResult(map[string]any{
|
||||
"port": bs.Port,
|
||||
"listening": bs.Listening,
|
||||
"queries": bs.Queries,
|
||||
"last_query": bs.LastQuery,
|
||||
"last_snapshot": bs.LastSnap,
|
||||
"bridge": map[string]any{
|
||||
"port": bs.Port,
|
||||
"listening": bs.Listening,
|
||||
"queries": bs.Queries,
|
||||
"last_query": bs.LastQuery,
|
||||
"last_snapshot": bs.LastSnap,
|
||||
},
|
||||
"push": monitorPushSummary(deps),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user