fix(adminui): guard Alerts chip auto-clear against stale-timer race (review)

This commit is contained in:
Joseph Doherty
2026-06-11 09:38:58 -04:00
parent 19ec656cdc
commit 23a4a0093b
@@ -135,6 +135,7 @@ else
// Auto-clear timer for the per-row result chip (mirrors DriverStatusPanel): the chip is set in
// ShowOpResult and cleared 8 s later so it doesn't persist until the next action.
private System.Threading.Timer? _opResultClearTimer;
private object? _opResultClearToken;
// Per-row timed-shelve duration (minutes). Keyed by AlarmId so each row's number input is
// independent — binding every row to one shared field would couple all the inputs together.
@@ -240,13 +241,20 @@ else
StateHasChanged();
// Auto-clear the result chip after 8 s (mirrors DriverStatusPanel). System.Threading.Timer
// is used (not System.Timers.Timer) so DisposeAsync can drain any in-flight callback.
var token = _opResultClearToken = new object();
_opResultClearTimer?.Dispose();
_opResultClearTimer = new System.Threading.Timer(_ =>
{
_opResultMessage = null;
_opResultAlarmId = "";
InvokeAsync(StateHasChanged);
}, null, TimeSpan.FromSeconds(8), Timeout.InfiniteTimeSpan);
InvokeAsync(() =>
{
// Ignore a stale fire: a newer action superseded this timer's chip. (Timer.Dispose does
// not drain an already-queued callback, so without this a stale timer could clear a
// freshly-set result from a different row.)
if (!ReferenceEquals(_opResultClearToken, token)) return;
_opResultMessage = null;
_opResultAlarmId = "";
StateHasChanged();
}),
null, TimeSpan.FromSeconds(8), Timeout.InfiniteTimeSpan);
}
private void OnAlarm(AlarmTransitionEvent evt) =>