Fix UI thread deadlock in fleet alert acknowledgment

- Acknowledgment now marks locally first, then posts to server in background
- Status check timer runs async properly without blocking UI thread
- Both changes use Task.Run to avoid .GetAwaiter().GetResult() deadlocks
- Bump tray to 1.6.4, agent to 1.13.3
This commit is contained in:
Proudlock
2026-09-08 18:16:27 -04:00
parent a504cbf1f6
commit 57f7225195
4 changed files with 43 additions and 30 deletions

View File

@@ -68,26 +68,33 @@ internal sealed class FleetAlertForm : Form
statusCheckTimer.Start();
}
private async void StatusCheckTimer_Tick(object? sender, EventArgs e)
private void StatusCheckTimer_Tick(object? sender, EventArgs e)
{
if (client == null || hostname == null)
return;
try
Task.Run(async () =>
{
var alerts = await client.FetchAlertsAsync(hostname, CancellationToken.None);
var stillActive = alerts?.Any(a => a.NotificationId == alert.NotificationId) ?? false;
if (!stillActive)
try
{
statusCheckTimer?.Stop();
Close();
var alerts = await client.FetchAlertsAsync(hostname, CancellationToken.None)
.ConfigureAwait(false);
var stillActive = alerts?.Any(a => a.NotificationId == alert.NotificationId) ?? false;
if (!stillActive)
{
BeginInvoke(new Action(() =>
{
statusCheckTimer?.Stop();
Close();
}));
}
}
}
catch
{
// Ignore errors - keep the form open if we can't check status
}
catch
{
// Ignore errors - keep the form open if we can't check status
}
});
}
private void ApplyRoundedCorners()

View File

@@ -159,24 +159,25 @@ internal sealed class FleetAlertWorker : IDisposable
private void OnAlertAcknowledged(FleetAlert alert, CancellationToken token)
{
try
{
logger.LogInformation(
"Fleet alert {NotificationId} acknowledged; posting to server.", alert.NotificationId);
logger.LogInformation(
"Fleet alert {NotificationId} acknowledged; queuing server post.", alert.NotificationId);
client.AcknowledgeAlertAsync(alert.NotificationId, assetId, hostname, token)
.GetAwaiter()
.GetResult();
store.MarkAcknowledged(alert.NotificationId);
store.MarkAcknowledged(alert.NotificationId);
logger.LogInformation("Fleet alert {NotificationId} recorded.", alert.NotificationId);
}
catch (Exception exception)
Task.Run(async () =>
{
logger.LogWarning(exception,
"Could not acknowledge fleet alert {NotificationId}; will retry on next poll.",
alert.NotificationId);
}
try
{
await client.AcknowledgeAlertAsync(alert.NotificationId, assetId, hostname, token);
logger.LogInformation("Fleet alert {NotificationId} posted to server.", alert.NotificationId);
}
catch (Exception exception)
{
logger.LogWarning(exception,
"Could not post acknowledgment for fleet alert {NotificationId}; already marked locally.",
alert.NotificationId);
}
});
}
public void Dispose()

View File

@@ -79,7 +79,10 @@
<!-- 1.6.3: auto-close when notification becomes inactive. Fleet alert forms now
check every 30 seconds if the notification is still active on the server and
automatically close if it has ended or been deactivated. -->
<Version>1.6.3</Version>
<!-- 1.6.4: fix UI thread deadlock. Acknowledgment and status checks now run async
properly without blocking the UI thread. Acknowledgment is marked locally first,
then posted to server in background to prevent lockups. -->
<Version>1.6.4</Version>
<InvariantGlobalization>true</InvariantGlobalization>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>

View File

@@ -175,7 +175,9 @@
No agent code changes, but deployed together for version consistency. -->
<!-- 1.13.2: coordinated release with tray 1.6.3 (auto-close when inactive, crash fix).
No agent code changes, but deployed together for version consistency. -->
<Version>1.13.2</Version>
<!-- 1.13.3: coordinated release with tray 1.6.4 (deadlock fix).
No agent code changes, but deployed together for version consistency. -->
<Version>1.13.3</Version>
<InvariantGlobalization>true</InvariantGlobalization>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>