feat: replace debug view polling with real-time SignalR streaming

The debug view polled every 2s by re-subscribing for full snapshots. Now a
persistent DebugStreamBridgeActor on central subscribes once and receives
incremental Akka stream events from the site, forwarding them to the Blazor
component via callbacks and to the CLI via a new SignalR hub at
/hubs/debug-stream. Adds `debug stream` CLI command with auto-reconnect.
This commit is contained in:
Joseph Doherty
2026-03-21 01:34:53 -04:00
parent d91aa83665
commit fd2e96fea2
15 changed files with 777 additions and 75 deletions

View File

@@ -19,12 +19,12 @@ Central cluster only. Sites have no user interface.
- A **load balancer** sits in front of the central cluster and routes to the active node.
- On central failover, the Blazor Server SignalR circuit is interrupted. The browser automatically attempts to reconnect via SignalR's built-in reconnection logic.
- Since sessions use **authentication cookies** carrying an embedded JWT (not server-side state), the user's authentication survives failover — the new active node validates the same cookie-embedded JWT. No re-login required if the token is still valid.
- Active debug view polling and in-progress deployment status subscriptions are lost on failover and must be re-opened by the user.
- Active debug view streams and in-progress deployment status subscriptions are lost on failover and must be re-opened by the user.
- Both central nodes share the same **ASP.NET Data Protection keys** (stored in the configuration database or shared configuration) so that tokens and anti-forgery tokens remain valid across failover.
## Real-Time Updates
- **Debug view**: Near-real-time display of attribute values and alarm states, updated via a **2-second polling timer**. This avoids the complexity of cross-cluster streaming while providing responsive feedback — 2s latency is imperceptible for debugging purposes.
- **Debug view**: Real-time display of attribute values and alarm states via **streaming**. When the user opens a debug view, a `DebugStreamBridgeActor` on the central side subscribes to the site's Akka stream for the selected instance. The bridge actor delivers an initial `DebugViewSnapshot` followed by ongoing `AttributeValueChanged` and `AlarmStateChanged` events to the Blazor component via callbacks, which call `InvokeAsync(StateHasChanged)` to push UI updates through the built-in SignalR circuit.
- **Health dashboard**: Site status, connection health, error rates, and buffer depths update via a **10-second auto-refresh timer**. Since health reports arrive from sites every 30 seconds, a 10s poll interval catches updates within one reporting cycle without unnecessary overhead.
- **Deployment status**: Pending/in-progress/success/failed transitions **push to the UI immediately** via SignalR (built into Blazor Server). No polling required for deployment tracking.
@@ -100,8 +100,11 @@ Central cluster only. Sites have no user interface.
### Debug View (Deployment Role)
- Select a deployed instance and open a live debug view.
- Near-real-time polling (2s interval) of all attribute values (with quality and timestamp) and alarm states for that instance.
- Initial snapshot of current state followed by periodic polling for updates.
- Real-time streaming of all attribute values (with quality and timestamp) and alarm states for that instance.
- The `DebugStreamService` creates a `DebugStreamBridgeActor` on the central side that subscribes to the site's Akka stream for the selected instance.
- The bridge actor receives an initial `DebugViewSnapshot` followed by ongoing `AttributeValueChanged` and `AlarmStateChanged` events from the site.
- Events are delivered to the Blazor component via callbacks, which call `InvokeAsync(StateHasChanged)` to push UI updates through the built-in SignalR circuit.
- A pulsing "Live" indicator replaces the static "Connected" badge when streaming is active.
- Stream includes attribute values formatted as `[InstanceUniqueName].[AttributePath].[AttributeName]` and alarm states formatted as `[InstanceUniqueName].[AlarmName]`.
- Subscribe-on-demand — stream starts when opened, stops when closed.