diff --git a/src/ZB.MOM.WW.MxGateway.Worker.Tests/Ipc/WorkerPipeSessionTests.cs b/src/ZB.MOM.WW.MxGateway.Worker.Tests/Ipc/WorkerPipeSessionTests.cs
index 1bef756..dca5936 100644
--- a/src/ZB.MOM.WW.MxGateway.Worker.Tests/Ipc/WorkerPipeSessionTests.cs
+++ b/src/ZB.MOM.WW.MxGateway.Worker.Tests/Ipc/WorkerPipeSessionTests.cs
@@ -1525,9 +1525,12 @@ public sealed class WorkerPipeSessionTests
// activity timestamp stopped advancing would accumulate staleness past the ceiling and
// fault — and require the beats to have actually flowed while it ran, so an inspection
// that saw a couple of frames and timed out cannot pass for a clean window. None may be a
- // WorkerFault while activity is continuously refreshed. The window stays well inside
- // FakeRuntimeSession's 5 s dispatch-block ceiling, so the command is still in flight
- // throughout.
+ // WorkerFault while activity is continuously refreshed. Nothing here is racing
+ // FakeRuntimeSession's blocked-dispatch backstop: that wait is a safety net sized far above
+ // any window a test opens (and above this test's own cancellation), so the command stays in
+ // flight for however long a loaded box stretches the loop. Were the two close together, a
+ // slow run would take the reply mid-window and then fail waiting for a reply already gone
+ // by — a cancellation at teardown, naming nothing.
TimeSpan inspectionWindow = TimeSpan.FromSeconds(2);
const int minimumFramesInspected = 30;
Stopwatch inspection = Stopwatch.StartNew();
diff --git a/src/ZB.MOM.WW.MxGateway.Worker.Tests/TestSupport/FakeRuntimeSession.cs b/src/ZB.MOM.WW.MxGateway.Worker.Tests/TestSupport/FakeRuntimeSession.cs
index c7b9ebf..0f89658 100644
--- a/src/ZB.MOM.WW.MxGateway.Worker.Tests/TestSupport/FakeRuntimeSession.cs
+++ b/src/ZB.MOM.WW.MxGateway.Worker.Tests/TestSupport/FakeRuntimeSession.cs
@@ -20,6 +20,17 @@ namespace ZB.MOM.WW.MxGateway.Worker.Tests.TestSupport;
///
internal sealed class FakeRuntimeSession : IWorkerRuntimeSession
{
+ ///
+ /// Backstop on the wait so a test that never releases leaves no
+ /// thread parked forever. It is a safety net, never a scenario's timing budget: nothing
+ /// asserts on it firing, and a test whose blocked window outruns it silently gets its reply
+ /// mid-window, which then fails as an opaque cancellation somewhere later. Kept far above
+ /// any test's window — and above the 20 s cancellation those tests arm — so the test's own
+ /// token always fails first, with its own message. releases the wait
+ /// regardless, so teardown never depends on this elapsing.
+ ///
+ private static readonly TimeSpan BlockedDispatchSafetyNet = TimeSpan.FromSeconds(30);
+
private readonly ManualResetEventSlim releaseDispatch = new(false);
private readonly object gate = new();
private readonly Queue events = new();
@@ -91,7 +102,7 @@ internal sealed class FakeRuntimeSession : IWorkerRuntimeSession
if (BlockDispatch)
{
- releaseDispatch.Wait(TimeSpan.FromSeconds(5));
+ releaseDispatch.Wait(BlockedDispatchSafetyNet);
}
SetSnapshot(new WorkerRuntimeHeartbeatSnapshot(