perf(ui): shared KPI cache, live-cache-backed alarm summary, coalesced debug renders

This commit is contained in:
Joseph Doherty
2026-08-14 20:53:38 -04:00
parent ee193cd2bb
commit 8c0b36b2fa
19 changed files with 1554 additions and 64 deletions
@@ -7,7 +7,7 @@
@using ZB.MOM.WW.ScadaBridge.Commons.Types.Kpi
@using ZB.MOM.WW.ScadaBridge.Communication
@using ZB.MOM.WW.ScadaBridge.CentralUI.Services
@inject CommunicationService CommunicationService
@inject IKpiSnapshotCache KpiSnapshots
@inject ISiteRepository SiteRepository
@inject IKpiHistoryQueryService KpiHistory
@inject ILogger<NotificationKpis> Logger
@@ -250,15 +250,24 @@
Logger.LogWarning(ex, "Failed to load sites for the KPI per-site breakdown.");
}
await RefreshAll();
// First load rides whatever the shared KPI cache already holds fresh; the
// Refresh button forces a new query (see RefreshAll).
await LoadAllAsync(forceRefresh: false);
}
private async Task RefreshAll()
// The operator's explicit Refresh bypasses the shared cache's freshness window.
private Task RefreshAll() => LoadAllAsync(forceRefresh: true);
private async Task LoadAllAsync(bool forceRefresh)
{
_loading = true;
// Race-free despite all tasks mutating component fields: Blazor Server runs
// every continuation on the circuit's single-threaded synchronization context.
await Task.WhenAll(LoadGlobalKpis(), LoadPerSiteKpis(), LoadPerNodeKpis(), LoadTrends());
await Task.WhenAll(
LoadGlobalKpis(forceRefresh),
LoadPerSiteKpis(forceRefresh),
LoadPerNodeKpis(forceRefresh),
LoadTrends());
_loading = false;
}
@@ -320,12 +329,11 @@
}
}
private async Task LoadGlobalKpis()
private async Task LoadGlobalKpis(bool forceRefresh)
{
try
{
var response = await CommunicationService.GetNotificationKpisAsync(
new NotificationKpiRequest(Guid.NewGuid().ToString("N")));
var response = await KpiSnapshots.GetNotificationKpisAsync(forceRefresh);
if (response.Success)
{
_kpi = response;
@@ -342,12 +350,11 @@
}
}
private async Task LoadPerSiteKpis()
private async Task LoadPerSiteKpis(bool forceRefresh)
{
try
{
var response = await CommunicationService.GetPerSiteNotificationKpisAsync(
new PerSiteNotificationKpiRequest(Guid.NewGuid().ToString("N")));
var response = await KpiSnapshots.GetPerSiteNotificationKpisAsync(forceRefresh);
if (response.Success)
{
_perSite = response.Sites;
@@ -364,12 +371,11 @@
}
}
private async Task LoadPerNodeKpis()
private async Task LoadPerNodeKpis(bool forceRefresh)
{
try
{
var response = await CommunicationService.GetPerNodeNotificationKpisAsync(
new PerNodeNotificationKpiRequest(Guid.NewGuid().ToString("N")));
var response = await KpiSnapshots.GetPerNodeNotificationKpisAsync(forceRefresh);
if (response.Success)
{
_perNode = response.Nodes;