feat(dashboard): AlarmsPage reads provider status from IGatewayAlarmService in-process
This commit is contained in:
@@ -1,10 +1,9 @@
|
|||||||
@page "/alarms"
|
@page "/alarms"
|
||||||
@implements IAsyncDisposable
|
@implements IAsyncDisposable
|
||||||
@using Microsoft.AspNetCore.SignalR.Client
|
@using ZB.MOM.WW.MxGateway.Server.Alarms
|
||||||
@using ZB.MOM.WW.MxGateway.Server.Dashboard.Hubs
|
|
||||||
@inject IDashboardLiveDataService LiveData
|
@inject IDashboardLiveDataService LiveData
|
||||||
@inject IOptions<GatewayOptions> GatewayOptions
|
@inject IOptions<GatewayOptions> GatewayOptions
|
||||||
@inject DashboardHubConnectionFactory HubFactory
|
@inject IGatewayAlarmService AlarmService
|
||||||
|
|
||||||
<PageTitle>Dashboard Alarms</PageTitle>
|
<PageTitle>Dashboard Alarms</PageTitle>
|
||||||
|
|
||||||
@@ -173,13 +172,13 @@
|
|||||||
private Task? _pollTask;
|
private Task? _pollTask;
|
||||||
|
|
||||||
private DashboardAlarmProviderStatus _providerStatus = DashboardAlarmProviderStatus.Healthy;
|
private DashboardAlarmProviderStatus _providerStatus = DashboardAlarmProviderStatus.Healthy;
|
||||||
private HubConnection? _alarmsHub;
|
private Task? _providerStatusTask;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
_pollTask = PollLoopAsync();
|
_pollTask = PollLoopAsync();
|
||||||
_ = AttachAlarmsHubAsync();
|
_providerStatusTask = ProviderStatusLoopAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string? ProviderStatusTitle()
|
private string? ProviderStatusTitle()
|
||||||
@@ -189,26 +188,48 @@
|
|||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AttachAlarmsHubAsync()
|
// The badge tracks the central monitor directly rather than looping back through
|
||||||
|
// /hubs/alarms: the alarm service is an in-process multi-subscriber fan-out, so a
|
||||||
|
// server-rendered page needs no SignalR client, no loopback socket and no auth token.
|
||||||
|
// Alarm rows still come from the 3-second poll below — this loop only feeds the badge.
|
||||||
|
private async Task ProviderStatusLoopAsync()
|
||||||
{
|
{
|
||||||
_alarmsHub = HubFactory.Create("/hubs/alarms");
|
while (!_cts.IsCancellationRequested)
|
||||||
_alarmsHub.On<AlarmFeedMessage>(AlarmsHub.AlarmMessage, async message =>
|
|
||||||
{
|
{
|
||||||
if (message.PayloadCase == AlarmFeedMessage.PayloadOneofCase.ProviderStatus)
|
try
|
||||||
{
|
{
|
||||||
|
await foreach (AlarmFeedMessage message in AlarmService
|
||||||
|
.StreamAsync(alarmFilterPrefix: null, _cts.Token)
|
||||||
|
.ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (message.PayloadCase != AlarmFeedMessage.PayloadOneofCase.ProviderStatus)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
_providerStatus = DashboardAlarmProviderStatus.FromFeed(message);
|
_providerStatus = DashboardAlarmProviderStatus.FromFeed(message);
|
||||||
await InvokeAsync(StateHasChanged).ConfigureAwait(false);
|
await InvokeAsync(StateHasChanged).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
try
|
|
||||||
{
|
{
|
||||||
await _alarmsHub.StartAsync(_cts.Token).ConfigureAwait(false);
|
return;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// The badge is best-effort; it stays at the healthy default until
|
// The monitor completes a subscriber's stream when it falls behind, and
|
||||||
// the hub reconnects and delivers a fresh provider-status message.
|
// again when the monitor restarts. Both are recoverable by resubscribing;
|
||||||
|
// the badge holds its last value in the meantime.
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(1), _cts.Token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,18 +333,6 @@
|
|||||||
{
|
{
|
||||||
await _cts.CancelAsync();
|
await _cts.CancelAsync();
|
||||||
|
|
||||||
if (_alarmsHub is not null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await _alarmsHub.DisposeAsync();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Disposal-time errors are best-effort.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_pollTask is not null)
|
if (_pollTask is not null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -335,6 +344,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_providerStatusTask is not null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _providerStatusTask;
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_cts.Dispose();
|
_cts.Dispose();
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user