perf(ipc): give worker pipes real OS buffers instead of zero-quota rendezvous

This commit is contained in:
Joseph Doherty
2026-08-15 12:02:43 -04:00
parent 9958f80026
commit da8463534b
2 changed files with 31 additions and 1 deletions
@@ -12,6 +12,18 @@ namespace ZB.MOM.WW.MxGateway.Server.Sessions;
/// <summary>Factory for creating worker clients and launching worker processes.</summary>
public sealed class SessionWorkerClientFactory : ISessionWorkerClientFactory
{
/// <summary>
/// Kernel buffer quota requested for each direction of a worker pipe. A zero quota — what the
/// short <see cref="NamedPipeServerStream"/> overloads request — makes every byte-mode write
/// rendezvous with a pending read, so writer latency is coupled to reader scheduling and a
/// writer with no reader parked blocks indefinitely. That is the failure class behind the
/// historical windev full-suite wedge (all tests reported, testhost never exiting). A real
/// quota lets a whole frame land in the kernel and the writer return. 128 KiB comfortably
/// holds the control traffic and typical event batches without reserving nonpaged pool per
/// session for the rare maximum-sized frame, which still streams through in chunks.
/// </summary>
private const int PipeBufferSizeBytes = 128 * 1024;
private readonly IWorkerProcessLauncher _workerProcessLauncher;
private readonly GatewayMetrics _metrics;
private readonly TimeProvider _timeProvider;
@@ -155,6 +167,11 @@ public sealed class SessionWorkerClientFactory : ISessionWorkerClientFactory
/// <summary>Creates a named pipe for worker communication.</summary>
/// <param name="pipeName">The pipe name.</param>
/// <returns>Named pipe server stream.</returns>
/// <remarks>
/// The buffer sizes are explicit so the pipe is not created with a zero quota; see
/// <see cref="PipeBufferSizeBytes"/>. On Unix hosts (the macOS test matrix, where named pipes
/// are Unix domain sockets) the sizes are advisory — the fix targets Windows production.
/// </remarks>
private static NamedPipeServerStream CreatePipe(string pipeName)
{
return new NamedPipeServerStream(
@@ -162,7 +179,9 @@ public sealed class SessionWorkerClientFactory : ISessionWorkerClientFactory
PipeDirection.InOut,
maxNumberOfServerInstances: 1,
PipeTransmissionMode.Byte,
PipeOptions.Asynchronous);
PipeOptions.Asynchronous,
inBufferSize: PipeBufferSizeBytes,
outBufferSize: PipeBufferSizeBytes);
}
/// <summary>Waits for a client to connect to the pipe.</summary>