Skip to content

fix(bx): invalidate monitor snapshot on box config changes - #146

Merged
sarg3nt merged 2 commits into
mainfrom
fix/bx-monitor-invalidate-on-config-change
May 19, 2026
Merged

fix(bx): invalidate monitor snapshot on box config changes#146
sarg3nt merged 2 commits into
mainfrom
fix/bx-monitor-invalidate-on-config-change

Conversation

@sarg3nt

@sarg3nt sarg3nt commented May 19, 2026

Copy link
Copy Markdown
Owner

Summary

Closes the "stale UI on /bx after box settings change" issue reported after the nsenter rollout:

  1. I had it enabled in the Bx settings for the Mjolnir container but it was disabled when we relaunched it, not sure how that happened.
  2. After enabling it, I went back to the grid and the console icon was not present. ... I went back to the box and confirmed the console feature was checked, it was, but I hit save again anyway and then back to the Bx dashboard and after a couple more refreshes, it showed up.

DB inspection confirmed console_enabled = 1 was always intact — the symptom was the statusMonitor's 30-second cache. /bx renders from the monitor's snapshot, so any DB-side toggle (Remote console, Enabled, …) didn't propagate until the next periodic poll.

Fix

Event-driven invalidation:

  • EventTypeBoxConfigChanged (box.config_changed) added to events/hub.go, with a PublishBoxConfigChanged(serverID) helper.
  • HAProxyBoxUpdatePost and HAProxyBoxTogglePost publish the event right after UpdateBox / SetBoxEnabled returns.
  • The Bx gear's Start subscribes to box.config_changed; the handler calls monitor.PokeBox(serverID).
  • statusMonitor.PokeBox(ctx, boxID) reads the row, runs one probe, and writes via m.set, which also broadcasts to SSE subscribers — so any open /bx tab updates in place without a refresh.
  • Deleted-box case: PokeBox drops the stale snapshot entry instead of leaving last-known-good values for a now-missing box.

Test plan

  • go build ./... green
  • go test ./internal/framework/handler/... ./internal/gears/bx/... ./internal/framework/events/... green
  • Toggle "Remote console" off → save → open /bx (within 1s) → shell icon gone for that box
  • Toggle "Remote console" on → save → open /bx → shell icon appears immediately
  • Toggle "Enabled" off in box list → /bx row goes gray immediately
  • Two browser tabs: /bx open in tab A, settings save in tab B → tab A's grid row updates via SSE without a refresh

🤖 Generated with Claude Code

The Bx status monitor polls every 30 seconds and caches each box's full
status (level, latency, last_checked, ConsoleEnabled, etc.) in an
in-memory snapshot. /bx renders from that snapshot.

Side effect: toggling a per-box setting (Remote console, Enabled, …)
in /settings/boxes did not show on /bx until the next 30s tick. User
report described this as "I had it enabled but it was disabled when we
relaunched" (no shell icon visible) plus "I went back to the box and
confirmed the console feature was checked, it was, but I hit save
again anyway and then back to the Bx dashboard and after a couple
more refreshes, it showed up."

Wiring:

- Add EventTypeBoxConfigChanged ("box.config_changed") + Hub.PublishBoxConfigChanged helper.
- HAProxyBoxUpdatePost and HAProxyBoxTogglePost publish the event
  immediately after UpdateBox / SetBoxEnabled returns.
- Bx Gear.Start subscribes to "box.config_changed" via deps.EventHub
  and calls monitor.PokeBox(serverID) for the affected box.
- New statusMonitor.PokeBox(ctx, boxID) fetches the row, runs a single
  probe, and writes the result via m.set — which also broadcasts to
  SSE subscribers, so any open /bx tab updates in place without a refresh.
- PokeBox handles the "box was deleted" case by dropping the stale
  snapshot entry instead of leaving last-known-good values for a
  now-missing box.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 19, 2026 04:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses stale data on the Bx fleet view (/bx) after box settings changes by introducing an event-driven cache invalidation path, so the Bx status monitor can refresh a single box’s snapshot immediately rather than waiting for the next 30s poll.

Changes:

  • Added a new event type (box.config_changed) and a helper publisher on the framework event hub.
  • Published the event after box update and enabled/disabled toggle actions in the HAProxy settings handlers.
  • Subscribed the Bx gear to the event and added statusMonitor.PokeBox to re-probe and update cached status for a single box.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
gearbox/internal/gears/bx/status.go Adds PokeBox to refresh a single box’s cached status out-of-band.
gearbox/internal/gears/bx/gear.go Subscribes Bx gear to box.config_changed to trigger PokeBox.
gearbox/internal/framework/handler/haproxy_config.go Publishes box.config_changed after UpdateBox / SetBoxEnabled operations.
gearbox/internal/framework/events/hub.go Adds EventTypeBoxConfigChanged and PublishBoxConfigChanged.

Comment thread gearbox/internal/gears/bx/status.go Outdated
Comment thread gearbox/internal/gears/bx/status.go
Comment thread gearbox/internal/gears/bx/gear.go
Comment thread gearbox/internal/gears/bx/gear.go
- Add statusMonitor.setAndBroadcast that always broadcasts to SSE
  subscribers; PokeBox now uses it so a config edit that flips only a
  non-level field (ConsoleEnabled, Enabled, Name, …) still pushes to
  open /bx tabs. The chatter-suppression in set() is desirable for
  the steady-state poll loop but defeats the purpose of an
  out-of-band config-change refresh.
- PokeBox now distinguishes transient DB errors from "not found":
  on err != nil we log and keep the last-known-good snapshot; only
  box == nil drops the cached entry. Avoids poisoning the UI when
  SQLite hiccups.
- Gear.Start stores the unsubscribe func returned by Subscribe and
  Gear.Stop now calls it before shutting the monitor down. Closes
  the events-adapter forwarder goroutine cleanly and stops new
  PokeBox calls from reaching a winding-down monitor.
- Subscribe call now references events.EventTypeBoxConfigChanged
  (cast to string for the gear.EventPublisher API) instead of a raw
  "box.config_changed" literal — keeps publisher and subscriber on
  the same constant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sarg3nt
sarg3nt merged commit 3ff9a4e into main May 19, 2026
22 checks passed
@sarg3nt
sarg3nt deleted the fix/bx-monitor-invalidate-on-config-change branch May 28, 2026 16:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants