feat(ipc): negotiate worker frame max, add gRPC headroom, bound DrainEvents (IPC-02/03/04 gateway half)
Proto foundation + gateway-side of the size/backpressure pass: - IPC-02: add GatewayHello.max_frame_bytes (regen Generated/); gateway sends its negotiated worker-frame max in the handshake so the worker can adopt it instead of a hard-coded default. Worker read-half lands separately. - IPC-03: give the pipe frame max envelope-overhead headroom above the public gRPC cap (WorkerFrameProtocolOptions.EnvelopeOverheadReserveBytes = 64 KiB; default Worker.MaxMessageBytes bumped to 16 MiB + reserve), cross-validate the headroom at startup, and pre-check command envelope size in WorkerClient so an oversized command fails only that correlation (ResourceExhausted) instead of faulting the whole session. - IPC-04: reject DrainEvents max_events above a public ceiling in the request validator (worker per-reply cap lands with the worker half). Docs: GatewayConfiguration, WorkerFrameProtocol, gateway.md. Tests: headroom validation, DrainEvents bound, oversized-command per-command failure (pipe-harness, verified on windev).
This commit is contained in:
@@ -187,7 +187,23 @@ public sealed class WorkerClient : IWorkerClient
|
||||
|
||||
try
|
||||
{
|
||||
await EnqueueAsync(CreateCommandEnvelope(correlationId, command), cancellationToken).ConfigureAwait(false);
|
||||
WorkerEnvelope commandEnvelope = CreateCommandEnvelope(correlationId, command);
|
||||
|
||||
// Reject an oversized command at the enqueue boundary so only this correlation fails
|
||||
// (ResourceExhausted) rather than the frame reaching the write loop and faulting the whole
|
||||
// session (IPC-03). Command envelopes are the only gateway-authored outbound payload whose
|
||||
// size the caller controls; checking here keeps a MessageTooLarge in the write loop a
|
||||
// genuine desync signal.
|
||||
int envelopeSize = commandEnvelope.CalculateSize();
|
||||
if (envelopeSize > _connection.FrameOptions.MaxMessageBytes)
|
||||
{
|
||||
throw new WorkerClientException(
|
||||
WorkerClientErrorCode.CommandTooLarge,
|
||||
$"Worker command {method} serializes to {envelopeSize} bytes, exceeding the negotiated "
|
||||
+ $"worker-frame maximum of {_connection.FrameOptions.MaxMessageBytes} bytes.");
|
||||
}
|
||||
|
||||
await EnqueueAsync(commandEnvelope, cancellationToken).ConfigureAwait(false);
|
||||
using CancellationTokenSource timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
Task timeoutTask = Task.Delay(timeout, timeoutCts.Token);
|
||||
Task<WorkerCommandReply> replyTask = pendingCommand.Task;
|
||||
@@ -910,6 +926,10 @@ public sealed class WorkerClient : IWorkerClient
|
||||
SupportedProtocolVersion = _connection.FrameOptions.ProtocolVersion,
|
||||
Nonce = _connection.Nonce,
|
||||
GatewayVersion = typeof(GatewayContractInfo).Assembly.GetName().Version?.ToString() ?? GatewayVersionFallback,
|
||||
|
||||
// Convey the negotiated worker-frame maximum so the worker adopts it instead of a
|
||||
// hard-coded default (IPC-02). Sits above the public gRPC cap by the envelope reserve.
|
||||
MaxFrameBytes = (uint)_connection.FrameOptions.MaxMessageBytes,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user