fix(WRK-22,WRK-24,WRK-25,WRK-27,IPC-26): worker write-seam hardening
WRK-22/IPC-26: tombstone a WriteAsync/WriteBatchAsync cancelled while waiting for the write lock (PendingFrame.Claimed under _gate; DequeueNext skips cancelled, claims the frame it returns) so a cancelled write never reaches the wire unless already claimed mid-write (documented residual). WRK-25: add WriteBatchAsync; RunEventDrainLoopAsync submits the drained event batch through it, so a burst of N events costs one flush not N. IPC-30 oversized-event structured fault preserved via FindOversizedEvent. WRK-24: reject a below-1024 negotiated frame maximum at the handshake (MinNegotiableFrameBytes, matching GatewayOptionsValidator floor). WRK-27: alarm poll advertises StaCallInProgress on the heartbeat snapshot so the watchdog suppresses to the ceiling, not the grace. Docs (WorkerFrameProtocol.md, MxAccessWorkerInstanceDesign.md) and the 2026-07-12 remediation registers/change-log updated in the same commit.
This commit is contained in:
@@ -24,6 +24,14 @@ public sealed class MxAccessStaSession : IWorkerRuntimeSession
|
||||
private CancellationTokenSource? alarmPollCts;
|
||||
private Task? alarmPollTask;
|
||||
private int? alarmConsumerThreadId;
|
||||
|
||||
// True on the STA thread exactly around the alarm PollOnce COM call. The alarm poll runs outside
|
||||
// the StaCommandDispatcher (so it does not inflate PendingCommandCount or perturb command dispatch
|
||||
// ordering), which means CaptureHeartbeat would otherwise see no in-flight activity during a long
|
||||
// poll and the watchdog would fault the session at the 15 s grace instead of the 75 s ceiling
|
||||
// granted to dispatched commands. Surfacing the poll on the heartbeat closes that asymmetry
|
||||
// (WRK-27). Volatile: written on the STA thread, read on the heartbeat thread.
|
||||
private volatile bool staAlarmPollInProgress;
|
||||
private bool disposed;
|
||||
|
||||
/// <summary>
|
||||
@@ -247,8 +255,20 @@ public sealed class MxAccessStaSession : IWorkerRuntimeSession
|
||||
await staRuntime.InvokeAsync(
|
||||
() =>
|
||||
{
|
||||
EnsureOnAlarmConsumerThread();
|
||||
handler.PollOnce();
|
||||
// Advertise the poll to the watchdog for exactly the span of the COM call
|
||||
// (WRK-27): set on the STA thread immediately before the affinity check and
|
||||
// PollOnce, clear in the finally so a heartbeat captured mid-poll reports
|
||||
// StaCallInProgress and one captured after does not.
|
||||
staAlarmPollInProgress = true;
|
||||
try
|
||||
{
|
||||
EnsureOnAlarmConsumerThread();
|
||||
handler.PollOnce();
|
||||
}
|
||||
finally
|
||||
{
|
||||
staAlarmPollInProgress = false;
|
||||
}
|
||||
},
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
@@ -377,7 +397,8 @@ public sealed class MxAccessStaSession : IWorkerRuntimeSession
|
||||
pendingCommandCount,
|
||||
(uint)eventQueue.Count,
|
||||
eventQueue.LastEventSequence,
|
||||
currentCommandCorrelationId);
|
||||
currentCommandCorrelationId,
|
||||
staAlarmPollInProgress);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
Reference in New Issue
Block a user