From 8f0f06ae25acbabbf8d3cf8296308819559b3b6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesko=20Ansch=C3=BCtz?= Date: Sun, 22 Mar 2026 18:27:44 +0100 Subject: [PATCH] Transportiere Server-Connectivity im Statuspfad Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- DEVELOPMENT.md | 1 + docs/PLAYER-STATUS-HTTP.md | 4 ++++ player/agent/internal/app/app.go | 1 + player/agent/internal/statusreporter/reporter.go | 3 +++ player/agent/internal/statusreporter/reporter_test.go | 10 ++++++++++ server/backend/internal/httpapi/playerstatus.go | 2 ++ server/backend/internal/httpapi/playerstatus_store.go | 1 + server/backend/internal/httpapi/playerstatus_test.go | 10 ++++++++++ 8 files changed, 32 insertions(+) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index b61a196..525c386 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -200,6 +200,7 @@ Ergaenzt seit dem ersten Geruest: - strukturierte Agent-Logs mit internem Health-Snapshot und signalgesteuertem Shutdown - erster periodischer HTTP-Status-Reporter im Agent - Server-Connectivity-Zustand im Agent (`unknown`, `online`, `degraded`, `offline`) auf Basis der Report-Ergebnisse +- der HTTP-Statuspfad transportiert jetzt neben `status` auch `server_connectivity` - lokales Compose-Grundgeruest fuer PostgreSQL und Mosquitto ## Arbeitsweise diff --git a/docs/PLAYER-STATUS-HTTP.md b/docs/PLAYER-STATUS-HTTP.md index 9bbb525..e8b8932 100644 --- a/docs/PLAYER-STATUS-HTTP.md +++ b/docs/PLAYER-STATUS-HTTP.md @@ -26,6 +26,7 @@ Mindestens enthalten: Aktuell zusaetzlich enthalten: +- `server_connectivity` - `server_url` - `mqtt_broker` - `heartbeat_every_seconds` @@ -39,6 +40,7 @@ Aktuell zusaetzlich enthalten: "screen_id": "info01-dev", "ts": "2026-03-22T16:00:00Z", "status": "running", + "server_connectivity": "online", "server_url": "http://127.0.0.1:8080", "mqtt_broker": "tcp://127.0.0.1:1883", "heartbeat_every_seconds": 30, @@ -68,6 +70,8 @@ Zusätzlich zur Write-Route gibt es in dieser Stufe: Dieser Endpunkt liefert den zuletzt akzeptierten Status fuer einen Screen zurueck. Wenn fuer den Screen noch kein Status vorliegt, liefert das Backend `404` mit dem gemeinsamen Fehlerumschlag. +Der aktuell zurueckgelieferte Datensatz enthaelt damit sowohl den Lifecycle-Status (`status`) als auch den vom Agenten lokal abgeleiteten Reachability-Zustand (`server_connectivity`). + ## Abgrenzung Noch nicht Teil dieser Stufe: diff --git a/player/agent/internal/app/app.go b/player/agent/internal/app/app.go index 9b27cab..4c080ff 100644 --- a/player/agent/internal/app/app.go +++ b/player/agent/internal/app/app.go @@ -176,6 +176,7 @@ func (a *App) reportStatus(ctx context.Context) { err := a.reporter.Send(ctx, statusreporter.Snapshot{ Status: string(snapshot.Status), + ServerConnectivity: string(snapshot.ServerConnectivity), ScreenID: snapshot.ScreenID, ServerBaseURL: snapshot.ServerBaseURL, MQTTBroker: snapshot.MQTTBroker, diff --git a/player/agent/internal/statusreporter/reporter.go b/player/agent/internal/statusreporter/reporter.go index 76741f9..d5edecb 100644 --- a/player/agent/internal/statusreporter/reporter.go +++ b/player/agent/internal/statusreporter/reporter.go @@ -12,6 +12,7 @@ import ( type Snapshot struct { Status string + ServerConnectivity string ScreenID string ServerBaseURL string MQTTBroker string @@ -24,6 +25,7 @@ type statusPayload struct { ScreenID string `json:"screen_id"` Timestamp string `json:"ts"` Status string `json:"status"` + ServerConnectivity string `json:"server_connectivity"` ServerURL string `json:"server_url"` MQTTBroker string `json:"mqtt_broker"` HeartbeatEverySeconds int `json:"heartbeat_every_seconds"` @@ -88,6 +90,7 @@ func buildPayload(snapshot Snapshot, now time.Time) statusPayload { ScreenID: snapshot.ScreenID, Timestamp: now.Format(time.RFC3339), Status: snapshot.Status, + ServerConnectivity: snapshot.ServerConnectivity, ServerURL: snapshot.ServerBaseURL, MQTTBroker: snapshot.MQTTBroker, HeartbeatEverySeconds: snapshot.HeartbeatEverySeconds, diff --git a/player/agent/internal/statusreporter/reporter_test.go b/player/agent/internal/statusreporter/reporter_test.go index 7ca17cc..7478ccd 100644 --- a/player/agent/internal/statusreporter/reporter_test.go +++ b/player/agent/internal/statusreporter/reporter_test.go @@ -14,6 +14,7 @@ func TestBuildPayloadFromSnapshot(t *testing.T) { lastHeartbeatAt := time.Date(2026, 3, 22, 16, 0, 0, 0, time.UTC) snapshot := Snapshot{ Status: "running", + ServerConnectivity: "online", ScreenID: "info01-dev", ServerBaseURL: "http://127.0.0.1:8080", MQTTBroker: "tcp://127.0.0.1:1883", @@ -36,6 +37,10 @@ func TestBuildPayloadFromSnapshot(t *testing.T) { t.Fatalf("StartedAt = %q, want %q", got, want) } + if got, want := payload.ServerConnectivity, "online"; got != want { + t.Fatalf("ServerConnectivity = %q, want %q", got, want) + } + if got, want := payload.LastHeartbeatAt, lastHeartbeatAt.Format(time.RFC3339); got != want { t.Fatalf("LastHeartbeatAt = %q, want %q", got, want) } @@ -67,6 +72,7 @@ func TestReporterSendStatus(t *testing.T) { err := reporter.Send(context.Background(), Snapshot{ Status: "running", + ServerConnectivity: "online", ScreenID: "info01-dev", ServerBaseURL: "http://127.0.0.1:8080", MQTTBroker: "tcp://127.0.0.1:1883", @@ -81,4 +87,8 @@ func TestReporterSendStatus(t *testing.T) { if got, want := received.ScreenID, "info01-dev"; got != want { t.Fatalf("received.ScreenID = %q, want %q", got, want) } + + if got, want := received.ServerConnectivity, "online"; got != want { + t.Fatalf("received.ServerConnectivity = %q, want %q", got, want) + } } diff --git a/server/backend/internal/httpapi/playerstatus.go b/server/backend/internal/httpapi/playerstatus.go index 2f4fb51..af98b46 100644 --- a/server/backend/internal/httpapi/playerstatus.go +++ b/server/backend/internal/httpapi/playerstatus.go @@ -10,6 +10,7 @@ type playerStatusRequest struct { ScreenID string `json:"screen_id"` Timestamp string `json:"ts"` Status string `json:"status"` + ServerConnectivity string `json:"server_connectivity"` ServerURL string `json:"server_url"` MQTTBroker string `json:"mqtt_broker"` HeartbeatEverySeconds int `json:"heartbeat_every_seconds"` @@ -59,6 +60,7 @@ func handlePlayerStatus(store playerStatusStore) http.HandlerFunc { ScreenID: request.ScreenID, Timestamp: request.Timestamp, Status: request.Status, + ServerConnectivity: request.ServerConnectivity, ServerURL: request.ServerURL, MQTTBroker: request.MQTTBroker, HeartbeatEverySeconds: request.HeartbeatEverySeconds, diff --git a/server/backend/internal/httpapi/playerstatus_store.go b/server/backend/internal/httpapi/playerstatus_store.go index 37b5dd9..1291347 100644 --- a/server/backend/internal/httpapi/playerstatus_store.go +++ b/server/backend/internal/httpapi/playerstatus_store.go @@ -6,6 +6,7 @@ type playerStatusRecord struct { ScreenID string `json:"screen_id"` Timestamp string `json:"ts"` Status string `json:"status"` + ServerConnectivity string `json:"server_connectivity,omitempty"` ServerURL string `json:"server_url,omitempty"` MQTTBroker string `json:"mqtt_broker,omitempty"` HeartbeatEverySeconds int `json:"heartbeat_every_seconds,omitempty"` diff --git a/server/backend/internal/httpapi/playerstatus_test.go b/server/backend/internal/httpapi/playerstatus_test.go index baf0b10..9a7e920 100644 --- a/server/backend/internal/httpapi/playerstatus_test.go +++ b/server/backend/internal/httpapi/playerstatus_test.go @@ -14,6 +14,7 @@ func TestHandlePlayerStatusAccepted(t *testing.T) { "screen_id": "info01-dev", "ts": "2026-03-22T16:00:00Z", "status": "running", + "server_connectivity": "online", "server_url": "http://127.0.0.1:8080", "mqtt_broker": "tcp://127.0.0.1:1883", "heartbeat_every_seconds": 30, @@ -50,6 +51,10 @@ func TestHandlePlayerStatusAccepted(t *testing.T) { if got, want := stored.ScreenID, "info01-dev"; got != want { t.Fatalf("stored.ScreenID = %q, want %q", got, want) } + + if got, want := stored.ServerConnectivity, "online"; got != want { + t.Fatalf("stored.ServerConnectivity = %q, want %q", got, want) + } } func TestHandlePlayerStatusRejectsInvalidJSON(t *testing.T) { @@ -171,6 +176,7 @@ func TestHandleGetLatestPlayerStatus(t *testing.T) { ScreenID: "info01-dev", Timestamp: "2026-03-22T16:00:00Z", Status: "running", + ServerConnectivity: "degraded", ServerURL: "http://127.0.0.1:8080", MQTTBroker: "tcp://127.0.0.1:1883", HeartbeatEverySeconds: 30, @@ -196,6 +202,10 @@ func TestHandleGetLatestPlayerStatus(t *testing.T) { if got, want := response.ScreenID, "info01-dev"; got != want { t.Fatalf("response.ScreenID = %q, want %q", got, want) } + + if got, want := response.ServerConnectivity, "degraded"; got != want { + t.Fatalf("response.ServerConnectivity = %q, want %q", got, want) + } } func TestHandleGetLatestPlayerStatusNotFound(t *testing.T) {