Preserve framed reads across fake worker emission gates
ci / windows-x86 (push) Successful in 1m20s
ci / nightly-windev (push) Has been skipped
ci / java (push) Successful in 2m17s
ci / windows-x86 (pull_request) Successful in 1m25s
ci / nightly-windev (pull_request) Has been skipped
ci / java (pull_request) Successful in 2m27s
ci / portable (push) Successful in 9m43s
ci / portable (pull_request) Successful in 9m47s

This commit is contained in:
Joseph Doherty
2026-10-13 09:42:09 -04:00
parent 19920b13da
commit 42c120aa83
5 changed files with 213 additions and 50 deletions
@@ -685,19 +685,19 @@ public sealed class GatewayEndToEndMultiSubscriberTests
int advisedItemHandle = 0;
int emittedCount = 0;
// Read envelopes one at a time. Between each envelope, if we have a
// subscription and the gate is ready, emit an event before reading the
// next envelope. When _stopEmitting is set, drain the gate and read
// remaining envelopes (including shutdown) without emitting.
await using GatedWorkerEnvelopeReader incoming = new(
harness.ReadGatewayEnvelopeAsync, _emitGate, cancellationToken);
while (!cancellationToken.IsCancellationRequested)
{
// While subscribed and not stopped, try to emit gated events using
// a short-timeout peek at the gate — yield to incoming envelopes to
// avoid starving shutdown processing.
while (advisedServerHandle != 0
&& !_stopEmitting
&& await _emitGate.WaitAsync(millisecondsTimeout: 0).ConfigureAwait(false))
WorkerEnvelope? envelope = await incoming.ReadOrGateAsync(
advisedServerHandle != 0 && !_stopEmitting).ConfigureAwait(false);
if (envelope is null)
{
if (_stopEmitting)
{
continue;
}
int index = ++emittedCount;
await harness.EmitEventAsync(
MxEventFamily.OnDataChange,
@@ -714,20 +714,6 @@ public sealed class GatewayEndToEndMultiSubscriberTests
};
mxEvent.OnDataChange = new OnDataChangeEvent();
}).ConfigureAwait(false);
}
// Use a short timeout so the emit loop above is re-evaluated
// periodically — but long enough not to spam.
WorkerEnvelope? envelope = null;
try
{
using CancellationTokenSource readCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
readCts.CancelAfter(TimeSpan.FromMilliseconds(50));
envelope = await harness.ReadGatewayEnvelopeAsync(readCts.Token).ConfigureAwait(false);
}
catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
{
// Timed out waiting for an envelope — loop back to check gate / emit.
continue;
}