Fix hanging and timing-fragile WorkerClient event-channel tests
The Server-032 change made event-channel overflow wait EventChannelFullModeTimeout before faulting, instead of faulting instantly. Two pre-existing overflow tests were not updated and left EventChannelFullModeTimeout at its 5s default, which races the 5s TestTimeout: ReadLoop_WhenEventQueueOverflows_FaultsClient and ReadLoop_WhenClientFaults_KillsOwnedWorkerProcess. Pin it to 50ms in both so overflow faults promptly. EnqueueWorkerEvent_WhenChannelFullPastTimeout_FaultsWithRichDiagnostic wrote 6 events into a 4-slot channel, but the worker client faults while reading the 5th and its read loop then stops — the 6th event is never drained and the test's pipe write for it blocks forever on a full OS pipe buffer, hanging the test host. Write exactly 5 (4 to fill plus 1 to overflow) as the test comment already intends, and bound the post-fault event drain with TestTimeout so a future regression fails instead of hanging. No production change: the Server-031/032 WorkerClient logic is correct — these were test-only defects. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -128,6 +128,7 @@ public sealed class WorkerClientTests
|
|||||||
new WorkerClientOptions
|
new WorkerClientOptions
|
||||||
{
|
{
|
||||||
EventChannelCapacity = 1,
|
EventChannelCapacity = 1,
|
||||||
|
EventChannelFullModeTimeout = TimeSpan.FromMilliseconds(50),
|
||||||
HeartbeatGrace = TimeSpan.FromSeconds(30),
|
HeartbeatGrace = TimeSpan.FromSeconds(30),
|
||||||
HeartbeatCheckInterval = TimeSpan.FromSeconds(30),
|
HeartbeatCheckInterval = TimeSpan.FromSeconds(30),
|
||||||
});
|
});
|
||||||
@@ -163,6 +164,7 @@ public sealed class WorkerClientTests
|
|||||||
new WorkerClientOptions
|
new WorkerClientOptions
|
||||||
{
|
{
|
||||||
EventChannelCapacity = 1,
|
EventChannelCapacity = 1,
|
||||||
|
EventChannelFullModeTimeout = TimeSpan.FromMilliseconds(50),
|
||||||
HeartbeatGrace = TimeSpan.FromSeconds(30),
|
HeartbeatGrace = TimeSpan.FromSeconds(30),
|
||||||
HeartbeatCheckInterval = TimeSpan.FromSeconds(30),
|
HeartbeatCheckInterval = TimeSpan.FromSeconds(30),
|
||||||
},
|
},
|
||||||
@@ -483,10 +485,13 @@ public sealed class WorkerClientTests
|
|||||||
});
|
});
|
||||||
await CompleteHandshakeAsync(client, pipePair);
|
await CompleteHandshakeAsync(client, pipePair);
|
||||||
|
|
||||||
// Fill the channel plus one to force the overflow path. The gateway
|
// Fill the 4-slot channel and write exactly one more to force the
|
||||||
// never opens a StreamEvents consumer so the events stay in the
|
// overflow path. The gateway never opens a StreamEvents consumer, so
|
||||||
// bounded channel.
|
// the events stay buffered. Exactly five events are written: the
|
||||||
for (ulong sequence = 1; sequence <= 6; sequence++)
|
// worker client faults while reading the fifth, after which its read
|
||||||
|
// loop stops — a sixth event would never be drained and its pipe
|
||||||
|
// write would block forever on a full OS pipe buffer.
|
||||||
|
for (ulong sequence = 1; sequence <= 5; sequence++)
|
||||||
{
|
{
|
||||||
await pipePair.WorkerWriter.WriteAsync(
|
await pipePair.WorkerWriter.WriteAsync(
|
||||||
CreateEventEnvelope(sequence: sequence, MxEventFamily.OnDataChange));
|
CreateEventEnvelope(sequence: sequence, MxEventFamily.OnDataChange));
|
||||||
@@ -499,10 +504,13 @@ public sealed class WorkerClientTests
|
|||||||
Assert.Equal(WorkerClientState.Faulted, client.State);
|
Assert.Equal(WorkerClientState.Faulted, client.State);
|
||||||
|
|
||||||
// Reading the events channel after fault throws the propagated
|
// Reading the events channel after fault throws the propagated
|
||||||
// WorkerClientException carrying the rich diagnostic message.
|
// WorkerClientException carrying the rich diagnostic message. The
|
||||||
|
// drain is bounded by TestTimeout so a regression that leaves the
|
||||||
|
// channel uncompleted fails the test instead of hanging it.
|
||||||
|
using CancellationTokenSource drainTimeout = new(TestTimeout);
|
||||||
WorkerClientException fault = await Assert.ThrowsAsync<WorkerClientException>(async () =>
|
WorkerClientException fault = await Assert.ThrowsAsync<WorkerClientException>(async () =>
|
||||||
{
|
{
|
||||||
await foreach (WorkerEvent _ in client.ReadEventsAsync(CancellationToken.None))
|
await foreach (WorkerEvent _ in client.ReadEventsAsync(drainTimeout.Token))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user