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
@@ -80,14 +80,24 @@ public sealed class StaRuntime : IDisposable
public bool IsRunning => startedEvent.IsSet && !stoppedEvent.IsSet;
/// <summary>
/// Pumps any pending Windows messages on the calling thread. Intended
/// for commands that synchronously hold the STA (e.g. ReadBulk) and
/// must allow inbound MXAccess COM events to dispatch while they
/// wait. Callers must already be on the STA; the method is otherwise
/// safe (PeekMessage simply finds no messages).
/// Pumps any pending Windows messages on the calling thread and refreshes
/// the STA activity timestamp. Intended for commands that synchronously
/// hold the STA (e.g. ReadBulk) and must allow inbound MXAccess COM events
/// to dispatch while they wait. Because a long-running command invokes this
/// on every wait iteration, refreshing activity here keeps a busy STA from
/// being mistaken for a hung one: a healthy command that keeps pumping stays
/// fresh past <c>HeartbeatStuckCeiling</c>, while a genuinely stuck STA (no
/// pumping) still accrues staleness and faults correctly. Callers must
/// already be on the STA; the method is otherwise safe (PeekMessage simply
/// finds no messages).
/// </summary>
/// <returns>The number of messages pumped.</returns>
public int PumpPendingMessages() => messagePump.PumpPendingMessages();
public int PumpPendingMessages()
{
int pumpedMessages = messagePump.PumpPendingMessages();
MarkActivity();
return pumpedMessages;
}
/// <summary>
/// Starts the STA thread.