Use live MQTT readiness for server health checks
Test and deploy MQTT backend / test (push) Successful in 1m44s
Test and deploy MQTT backend / deploy (push) Successful in 14s

This commit is contained in:
2026-10-08 14:51:32 +03:30
parent 71ef622b4f
commit 9a32f634d4
5 changed files with 35 additions and 2 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ Open http://127.0.0.1:8080. If local port 8080 is occupied, use `-L 8081:127.0.0
The runner configuration allows `/opt/test-mqtt-5/backend` in `container.valid_volumes`; only the deploy job requests that mount as `/runtime`. The prior runner configuration is backed up before this addition. Existing frontend job mounts remain unchanged. This workflow assumes that label continues to use the same server Docker daemon; moving the runner requires updating the deployment arrangement. The runner configuration allows `/opt/test-mqtt-5/backend` in `container.valid_volumes`; only the deploy job requests that mount as `/runtime`. The prior runner configuration is backed up before this addition. Existing frontend job mounts remain unchanged. This workflow assumes that label continues to use the same server Docker daemon; moving the runner requires updating the deployment arrangement.
`deploy.sh` locks the runtime directory, validates Compose, preserves the previous image-tag file and Compose, deploys only backend, and checks container health for up to 60 seconds. Health requires the UI snapshot to report MQTT connected. Failed updates restore the previous release; a failed first deployment stops the backend. Images are retained for rollback. No host-wide image prune is run. Remote device return-path checks should still be performed after significant MQTT changes. `deploy.sh` locks the runtime directory, validates Compose, preserves the previous image-tag file and Compose, deploys only backend, and checks container health for up to 60 seconds. Health requires `/healthz` to confirm current MQTT readiness, independent of bounded event-history eviction. Failed updates restore the previous release; a failed first deployment stops the backend. Images are retained for rollback. No host-wide image prune is run. Remote device return-path checks should still be performed after significant MQTT changes.
## Server operations ## Server operations
+1
View File
@@ -168,6 +168,7 @@ func Run(ctx context.Context, args []string, out, errOut io.Writer, sim bool) in
var viewer *web.Viewer var viewer *web.Viewer
if cfg.Web.Enabled { if cfg.Web.Enabled {
viewer = web.New(cfg.Web, store, cfg.Deadlines.Shutdown) viewer = web.New(cfg.Web, store, cfg.Deadlines.Shutdown)
viewer.SetReadiness(client.Ready)
if err = viewer.Start(); err != nil { if err = viewer.Start(); err != nil {
fmt.Fprintln(errOut, err) fmt.Fprintln(errOut, err)
return 1 return 1
+16
View File
@@ -40,6 +40,7 @@ type Snapshot struct {
Compatibility []Compatibility `json:"compatibility"` Compatibility []Compatibility `json:"compatibility"`
} }
type Viewer struct { type Viewer struct {
ready func() bool
cfg config.Web cfg config.Web
store *events.Store store *events.Store
shutdown time.Duration shutdown time.Duration
@@ -60,10 +61,25 @@ func New(cfg config.Web, store *events.Store, shutdown time.Duration) *Viewer {
mux.Handle("GET /assets/", http.StripPrefix("/assets/", http.FileServer(http.FS(sub)))) mux.Handle("GET /assets/", http.StripPrefix("/assets/", http.FileServer(http.FS(sub))))
mux.HandleFunc("GET /api/snapshot", v.snapshot) mux.HandleFunc("GET /api/snapshot", v.snapshot)
mux.HandleFunc("GET /api/events", v.stream) mux.HandleFunc("GET /api/events", v.stream)
mux.HandleFunc("GET /healthz", v.health)
v.handler = v.guard(mux) v.handler = v.guard(mux)
v.server = &http.Server{Handler: v.handler, ReadHeaderTimeout: 3 * time.Second, IdleTimeout: 20 * time.Second, MaxHeaderBytes: 8 << 10} v.server = &http.Server{Handler: v.handler, ReadHeaderTimeout: 3 * time.Second, IdleTimeout: 20 * time.Second, MaxHeaderBytes: 8 << 10}
return v return v
} }
// SetReadiness must be called before Start. Readiness reflects live MQTT state,
// independent of connection events rolling out of the bounded viewer history.
func (v *Viewer) SetReadiness(ready func() bool) { v.ready = ready }
func (v *Viewer) health(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-store")
if v.ready == nil || !v.ready() {
http.Error(w, "MQTT not ready", http.StatusServiceUnavailable)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"status":"ready"}`))
}
func (v *Viewer) Address() string { func (v *Viewer) Address() string {
if v.listener == nil { if v.listener == nil {
return v.cfg.Address return v.cfg.Address
+16
View File
@@ -162,3 +162,19 @@ func TestReportedScenariosDoNotClaimHardwareCompatibility(t *testing.T) {
t.Fatal("scenario aliases retained history") t.Fatal("scenario aliases retained history")
} }
} }
func TestHealthUsesCurrentMQTTReadiness(t *testing.T) {
v := testViewer()
ready := false
v.SetReadiness(func() bool { return ready })
for _, want := range []int{503, 200, 503} {
ready = want == 200
// No connection event retained: current readiness must still work.
r := httptest.NewRequest("GET", "http://127.0.0.1:8080/healthz", nil)
w := httptest.NewRecorder()
v.Handler().ServeHTTP(w, r)
if w.Code != want {
t.Fatalf("health status %d, want %d", w.Code, want)
}
}
}
+1 -1
View File
@@ -45,7 +45,7 @@ services:
test: test:
- CMD-SHELL - CMD-SHELL
- >- - >-
wget -qO- http://127.0.0.1:18080/api/snapshot | grep -q '"connection":"connected"' wget -qO- http://127.0.0.1:18080/healthz >/dev/null
interval: 10s interval: 10s
timeout: 4s timeout: 4s
retries: 6 retries: 6