fix(WRK-01): STA pump step refreshes activity to prevent false StaHung

A long legitimate ReadBulk pumped Windows messages without refreshing
LastStaActivityUtc, so the watchdog false-positived StaHung past
HeartbeatStuckCeiling and then silently dropped every reply. PumpPendingMessages()
now calls MarkActivity() after pumping; a genuinely stuck STA (no pumping)
still accrues staleness and faults correctly. No MXAccess parity change.

archreview: WRK-01 (P0). Verified on the Windows host (x86): worker builds
clean, StaRuntimeTests + WorkerPipeSessionTests 33/33 pass.
This commit is contained in:
Joseph Doherty
2026-07-09 05:51:45 -04:00
parent 5faef6c012
commit 31eec41456
4 changed files with 161 additions and 15 deletions
@@ -85,6 +85,34 @@ public sealed class StaRuntimeTests
Assert.True(updated);
}
/// <summary>
/// Verifies that <see cref="StaRuntime.PumpPendingMessages"/> refreshes
/// <see cref="StaRuntime.LastActivityUtc"/>. A long synchronous STA
/// command (for example <c>ReadBulk</c> waiting <c>timeout_ms</c> for
/// the first <c>OnDataChange</c>) invokes the pump step on every wait
/// iteration while it legitimately holds the STA thread; refreshing
/// activity here keeps the watchdog from mistaking a busy STA for a hung
/// one (WRK-01). The runtime is deliberately left unstarted so the only
/// source of activity is the pump call under test, not the idle loop.
/// </summary>
[Fact]
public void PumpPendingMessages_RefreshesLastActivity()
{
RecordingComApartmentInitializer initializer = new();
using StaRuntime runtime = CreateRuntime(initializer);
DateTimeOffset before = runtime.LastActivityUtc;
bool refreshed = SpinWait.SpinUntil(
() =>
{
runtime.PumpPendingMessages();
return runtime.LastActivityUtc > before;
},
TimeSpan.FromSeconds(2));
Assert.True(refreshed, "PumpPendingMessages must advance LastActivityUtc.");
}
/// <summary>Verifies that InvokeAsync faults the returned task when a command raises an exception without stopping the runtime.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]