fix(central-ui): resolve CentralUI-006 — push-based deployment status via IDeploymentStatusNotifier, remove 10s polling timer
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
@inject IDeploymentManagerRepository DeploymentManagerRepository
|
||||
@inject ITemplateEngineRepository TemplateEngineRepository
|
||||
@inject ScadaLink.CentralUI.Auth.SiteScopeService SiteScope
|
||||
@inject ScadaLink.DeploymentManager.IDeploymentStatusNotifier DeploymentStatusNotifier
|
||||
@implements IDisposable
|
||||
|
||||
<div class="container-fluid mt-3">
|
||||
@@ -196,47 +197,42 @@
|
||||
private Dictionary<int, string> _instanceNames = new();
|
||||
private bool _loading = true;
|
||||
private string? _errorMessage;
|
||||
private Timer? _refreshTimer;
|
||||
private bool _autoRefresh = true;
|
||||
private readonly HashSet<string> _expandedErrors = new();
|
||||
|
||||
private int _currentPage = 1;
|
||||
private int _totalPages;
|
||||
private const int PageSize = 25;
|
||||
private static readonly TimeSpan RefreshInterval = TimeSpan.FromSeconds(10);
|
||||
|
||||
// CentralUI-006: deployment status updates are push-based, not polled.
|
||||
// DeploymentManager raises IDeploymentStatusNotifier.StatusChanged on every
|
||||
// deployment-record status write; this page subscribes to it and reloads,
|
||||
// and Blazor Server pushes the re-render to the browser over its SignalR
|
||||
// circuit — satisfying the design's "no polling required" requirement.
|
||||
// The notifier event is raised on the DeploymentManager service thread, so
|
||||
// the handler marshals onto the renderer via InvokeAsync.
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadDataAsync();
|
||||
StartTimer();
|
||||
DeploymentStatusNotifier.StatusChanged += OnDeploymentStatusChanged;
|
||||
}
|
||||
|
||||
private void StartTimer()
|
||||
private void OnDeploymentStatusChanged(ScadaLink.DeploymentManager.DeploymentStatusChange change)
|
||||
{
|
||||
_refreshTimer?.Dispose();
|
||||
_refreshTimer = new Timer(_ =>
|
||||
if (!_autoRefresh) return;
|
||||
_ = InvokeAsync(async () =>
|
||||
{
|
||||
InvokeAsync(async () =>
|
||||
{
|
||||
if (!_autoRefresh) return;
|
||||
await LoadDataAsync();
|
||||
StateHasChanged();
|
||||
});
|
||||
}, null, RefreshInterval, RefreshInterval);
|
||||
await LoadDataAsync();
|
||||
StateHasChanged();
|
||||
});
|
||||
}
|
||||
|
||||
private void ToggleAutoRefresh()
|
||||
{
|
||||
// When paused, incoming push notifications are ignored; "Refresh" still
|
||||
// forces a manual reload. No timer is involved either way.
|
||||
_autoRefresh = !_autoRefresh;
|
||||
if (_autoRefresh)
|
||||
{
|
||||
StartTimer();
|
||||
}
|
||||
else
|
||||
{
|
||||
_refreshTimer?.Dispose();
|
||||
_refreshTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsErrorExpanded(string deploymentId) => _expandedErrors.Contains(deploymentId);
|
||||
@@ -320,6 +316,8 @@
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_refreshTimer?.Dispose();
|
||||
// Unsubscribe so a status change after the circuit is gone does not
|
||||
// touch a disposed component (the notifier is a process singleton).
|
||||
DeploymentStatusNotifier.StatusChanged -= OnDeploymentStatusChanged;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user