fix(ipc): cancellation-priority timeout classification; structurally-enforced no-throw cancel send

This commit is contained in:
Joseph Doherty
2026-08-15 12:41:38 -04:00
parent 1742e38c10
commit a1a38b5538
3 changed files with 130 additions and 59 deletions
@@ -163,7 +163,7 @@ public sealed class WorkerClientTests
// The timeout also emits a WorkerCancel for the abandoned correlation (GWC-31), which sits
// ahead of the second command on the FIFO pipe; skip it rather than mistaking it for the
// command this assertion is about.
WorkerEnvelope secondCommand = await ReadNextCommandAsync(pipePair);
WorkerEnvelope secondCommand = await ReadNextCommandAsync(pipePair, timedOutCommand.CorrelationId);
await pipePair.WriteAsync(
CreateCommandReplyEnvelope(secondCommand.CorrelationId, MxCommandKind.GetWorkerInfo));
@@ -188,8 +188,10 @@ public sealed class WorkerClientTests
await using WorkerClient client = CreateClient(pipePair);
await CompleteHandshakeAsync(client, pipePair);
// Advise rather than a control command: control commands bypass the worker's STA queue, so a
// data command is the case the cancel actually exists for.
Task<WorkerCommandReply> invokeTask = client.InvokeAsync(
CreateCommand(MxCommandKind.Ping),
CreateCommand(MxCommandKind.Advise),
TimeSpan.FromMilliseconds(50),
CancellationToken.None);
@@ -1076,12 +1078,17 @@ public sealed class WorkerClientTests
}
/// <summary>
/// Reads gateway envelopes until a <c>WorkerCommand</c> arrives, skipping the control envelopes
/// (such as the <c>WorkerCancel</c> a command timeout emits) that may precede it on the FIFO pipe.
/// Reads gateway envelopes until a <c>WorkerCommand</c> arrives, skipping the <c>WorkerCancel</c>
/// a command timeout emits for <paramref name="canceledCorrelationId"/>. Anything else on the pipe
/// fails the test rather than being skipped: the point of the skip is to tolerate exactly the one
/// known interleaving, not to make the assertion blind to unexpected gateway traffic.
/// </summary>
/// <param name="pipePair">The connected pipe pair whose worker side is read.</param>
/// <param name="canceledCorrelationId">Correlation id of the timed-out command whose cancel is expected.</param>
/// <returns>The next command envelope written by the gateway.</returns>
private static async Task<WorkerEnvelope> ReadNextCommandAsync(PipePair pipePair)
private static async Task<WorkerEnvelope> ReadNextCommandAsync(
PipePair pipePair,
string canceledCorrelationId)
{
while (true)
{
@@ -1090,6 +1097,9 @@ public sealed class WorkerClientTests
{
return envelope;
}
Assert.Equal(WorkerEnvelope.BodyOneofCase.WorkerCancel, envelope.BodyCase);
Assert.Equal(canceledCorrelationId, envelope.CorrelationId);
}
}