From 93329087a90a9a8b8681037c04b0ccdf38c46659 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Thu, 7 May 2026 07:52:14 +0200 Subject: [PATCH] fix(messagemanager): warn loudly when DisposeAsync 10s timeout hits --- HellionChat/MessageManager.cs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/HellionChat/MessageManager.cs b/HellionChat/MessageManager.cs index 40dfb6e..adcc0b1 100644 --- a/HellionChat/MessageManager.cs +++ b/HellionChat/MessageManager.cs @@ -90,19 +90,22 @@ internal class MessageManager : IAsyncDisposable Plugin.ChatGui.ChatMessageUnhandled -= ChatMessage; await PendingThreadCancellationToken.CancelAsync(); - var timeout = 10_000; // 10s - while (timeout > 0) - { - if (!PendingMessageThread.IsAlive) - break; - timeout -= 100; + // 10s cooperative window; Thread.Abort is gone since .NET 5, so a + // stuck worker has to ride out the next AppDomain unload. + var deadline = TimeSpan.FromSeconds(10); + var stopwatch = Stopwatch.StartNew(); + while (stopwatch.Elapsed < deadline && PendingMessageThread.IsAlive) await Task.Delay(100); - Plugin.Log.Debug("Sleeping because PendingMessageThread thread still alive"); - } - // CancellationTokenSource owns an unmanaged WaitHandle; dispose after the - // worker thread has drained, otherwise it leaks across plugin reloads. + if (PendingMessageThread.IsAlive) + Plugin.Log.Warning( + "PendingMessageThread did not observe cancellation within 10s. " + + "Worker remains on a background thread; next plugin reload releases it. " + + "If this recurs, file a bug with /xllog after the previous reload."); + + // CTS owns an unmanaged WaitHandle; dispose even if the worker is + // alive — it checks IsCancellationRequested via the linked token. PendingThreadCancellationToken.Dispose(); Store.Dispose();