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:
@@ -68,26 +68,33 @@ internal sealed class FleetAlertForm : Form
|
|||||||
statusCheckTimer.Start();
|
statusCheckTimer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void StatusCheckTimer_Tick(object? sender, EventArgs e)
|
private void StatusCheckTimer_Tick(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (client == null || hostname == null)
|
if (client == null || hostname == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var alerts = await client.FetchAlertsAsync(hostname, CancellationToken.None);
|
try
|
||||||
var stillActive = alerts?.Any(a => a.NotificationId == alert.NotificationId) ?? false;
|
|
||||||
|
|
||||||
if (!stillActive)
|
|
||||||
{
|
{
|
||||||
statusCheckTimer?.Stop();
|
var alerts = await client.FetchAlertsAsync(hostname, CancellationToken.None)
|
||||||
Close();
|
.ConfigureAwait(false);
|
||||||
|
var stillActive = alerts?.Any(a => a.NotificationId == alert.NotificationId) ?? false;
|
||||||
|
|
||||||
|
if (!stillActive)
|
||||||
|
{
|
||||||
|
BeginInvoke(new Action(() =>
|
||||||
|
{
|
||||||
|
statusCheckTimer?.Stop();
|
||||||
|
Close();
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
catch
|
||||||
catch
|
{
|
||||||
{
|
// Ignore errors - keep the form open if we can't check status
|
||||||
// Ignore errors - keep the form open if we can't check status
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyRoundedCorners()
|
private void ApplyRoundedCorners()
|
||||||
|
|||||||
@@ -159,24 +159,25 @@ internal sealed class FleetAlertWorker : IDisposable
|
|||||||
|
|
||||||
private void OnAlertAcknowledged(FleetAlert alert, CancellationToken token)
|
private void OnAlertAcknowledged(FleetAlert alert, CancellationToken token)
|
||||||
{
|
{
|
||||||
try
|
logger.LogInformation(
|
||||||
{
|
"Fleet alert {NotificationId} acknowledged; queuing server post.", alert.NotificationId);
|
||||||
logger.LogInformation(
|
|
||||||
"Fleet alert {NotificationId} acknowledged; posting to server.", alert.NotificationId);
|
|
||||||
|
|
||||||
client.AcknowledgeAlertAsync(alert.NotificationId, assetId, hostname, token)
|
store.MarkAcknowledged(alert.NotificationId);
|
||||||
.GetAwaiter()
|
|
||||||
.GetResult();
|
|
||||||
|
|
||||||
store.MarkAcknowledged(alert.NotificationId);
|
Task.Run(async () =>
|
||||||
logger.LogInformation("Fleet alert {NotificationId} recorded.", alert.NotificationId);
|
|
||||||
}
|
|
||||||
catch (Exception exception)
|
|
||||||
{
|
{
|
||||||
logger.LogWarning(exception,
|
try
|
||||||
"Could not acknowledge fleet alert {NotificationId}; will retry on next poll.",
|
{
|
||||||
alert.NotificationId);
|
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()
|
public void Dispose()
|
||||||
|
|||||||
@@ -79,7 +79,10 @@
|
|||||||
<!-- 1.6.3: auto-close when notification becomes inactive. Fleet alert forms now
|
<!-- 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
|
check every 30 seconds if the notification is still active on the server and
|
||||||
automatically close if it has ended or been deactivated. -->
|
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>
|
<InvariantGlobalization>true</InvariantGlobalization>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
|
|||||||
@@ -175,7 +175,9 @@
|
|||||||
No agent code changes, but deployed together for version consistency. -->
|
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).
|
<!-- 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. -->
|
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>
|
<InvariantGlobalization>true</InvariantGlobalization>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
|
|||||||
Reference in New Issue
Block a user