ModernUO/Projects
Kamron Batman 6f74532280
fix(crowdsec): stop deadlocking and racing shutdown on the flush path
Two defects in CrowdSecReporter shutdown, both reachable only on a shard that
actually has CrowdSec configured with items still queued.

1. FlushRemainingOnStop blocked with GetAwaiter().GetResult() on a ValueTask.
   Beyond being unsupported in general -- an IValueTaskSource-backed ValueTask
   does not wait there, it throws -- it hung. Stop() runs on the main thread,
   where Main installs EventLoopContext as SynchronizationContext.Current, and
   nothing in CrowdSecAlertClient used ConfigureAwait(false), so the send's
   continuation was posted to a queue only LoopContext.ExecuteTasks() drains --
   and by HandleClosed() the loop has stopped ticking. The thread waited on a
   continuation only that thread could run. The 3s budget did not help: it
   completes the HTTP call, not the resumption.

   Run the flush through Task.Run so the whole chain lives on the pool with no
   context to capture, block once on a real Task, and bound it with Wait so a
   wedged send costs a few seconds of shutdown rather than the process. Add
   ConfigureAwait(false) across the client and drain loop per rule #10 so the
   pool hop is defense in depth rather than the only thing holding it up.

2. Start() did Task.Run(() => DrainLoop(...)) where DrainLoop returned
   ValueTask. There is no Task.Run(Func<ValueTask>) overload, so it bound to
   Task.Run<TResult>(Func<TResult>) and produced a Task<ValueTask> that
   completes at the first suspending await, not when the loop exits -- silently
   upcast by the Task _drainTask field. Stop()'s drain-exited handshake was
   therefore a no-op (Wait returned true in ~0ms), letting the flush read a
   SingleReader channel concurrently with a live drain loop, which is precisely
   the hazard that handshake documents itself as preventing. It also made the
   loop fire-and-forget and swallowed any fault escaping it.

   Return Task so it binds to Task.Run(Func<Task>) and unwraps. A loop awaited
   once has nothing to gain from ValueTask.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 11:07:30 -07:00
..
Application fix: Bumps dependencies. (#2531) 2026-07-14 15:17:55 -07:00
BuildTool fix: Bumps dependencies. (#2531) 2026-07-14 15:17:55 -07:00
Logger fix: Bumps dependencies. (#2531) 2026-07-14 15:17:55 -07:00
Server Cleanup 2026-07-25 10:57:07 -07:00
Server.Tests fix(tests): repair the build after the Configure/namespace sweep 2026-07-25 11:07:14 -07:00
UOContent fix(crowdsec): stop deadlocking and racing shutdown on the flush path 2026-07-25 11:07:30 -07:00
UOContent.Tests fix(tests): repair the build after the Configure/namespace sweep 2026-07-25 11:07:14 -07:00