feat(worker): adopt negotiated frame max, bound drain, priority write scheduler (IPC-02/04 + WRK-04/07 worker half)
Worker half of the Wave 3 size/backpressure + write-ordering pass: - IPC-02: the worker adopts GatewayHello.max_frame_bytes during the handshake (WorkerFrameProtocolOptions.AdoptNegotiatedMaxMessageBytes) instead of a hard-coded default; 0 keeps the default, a value above a 256 MiB ceiling is rejected. Reader and writer share the options instance, applied before the message loop. - IPC-04: DrainEvents caps each reply at MaxDrainEventsPerReply (10_000) and treats max_events = 0 as that cap rather than 'drain the entire queue', so one diagnostic drain cannot pack a session-killing reply frame. - WRK-04: WorkerFrameWriter stamps the envelope Sequence at the actual point of writing (under the write lock) instead of at envelope creation, so the on-wire order and the stamped sequence always agree under concurrent producers. - WRK-07: the writer is now a cooperative priority scheduler — callers enqueue at Control or Event priority and the draining lock-holder writes all control frames before any event frame, so replies/faults/heartbeats jump ahead of an event backlog. Per-frame validation/size rejections fail only that frame; a stream write failure fails all queued frames. Tests: monotonic gap-free sequence under concurrency, control-before-event priority (gated stream), negotiated-max adoption, DrainEvents zero-bound. Worker builds x86 only — verified on windev.
This commit is contained in:
@@ -10,6 +10,14 @@ public sealed class WorkerFrameProtocolOptions
|
||||
/// <summary>Default maximum message size in bytes (16 MB).</summary>
|
||||
public const int DefaultMaxMessageBytes = 16 * 1024 * 1024;
|
||||
|
||||
/// <summary>
|
||||
/// Upper ceiling the worker will accept for a gateway-negotiated frame maximum
|
||||
/// (<c>GatewayHello.max_frame_bytes</c>, IPC-02). Matches the gateway's own configuration ceiling
|
||||
/// so a nonsensical negotiated value is rejected at the handshake rather than driving an absurd
|
||||
/// per-frame allocation. 256 MiB.
|
||||
/// </summary>
|
||||
public const int MaxNegotiableFrameBytes = 256 * 1024 * 1024;
|
||||
|
||||
/// <summary>Initializes a new instance of the WorkerFrameProtocolOptions class from WorkerOptions.</summary>
|
||||
/// <param name="options">Worker initialization options.</param>
|
||||
public WorkerFrameProtocolOptions(WorkerOptions options)
|
||||
@@ -98,6 +106,36 @@ public sealed class WorkerFrameProtocolOptions
|
||||
/// <summary>Gets the nonce for startup validation.</summary>
|
||||
public string Nonce { get; }
|
||||
|
||||
/// <summary>Gets the maximum message size in bytes.</summary>
|
||||
public int MaxMessageBytes { get; }
|
||||
/// <summary>
|
||||
/// Gets the maximum worker-frame message size in bytes. Initialized from the constructor and
|
||||
/// then adopted once from the gateway-negotiated value during the startup handshake
|
||||
/// (<c>GatewayHello.max_frame_bytes</c>, IPC-02) via <see cref="AdoptNegotiatedMaxMessageBytes"/>,
|
||||
/// before the message loop starts. Not mutated afterwards, so the single-threaded handshake write
|
||||
/// is safe for the reader/writer that share this instance.
|
||||
/// </summary>
|
||||
public int MaxMessageBytes { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Adopts the gateway-negotiated frame maximum conveyed in <c>GatewayHello.max_frame_bytes</c>
|
||||
/// (IPC-02). A value of 0 (an older gateway that never set the field) is ignored and the
|
||||
/// constructor default is kept. A value above <see cref="MaxNegotiableFrameBytes"/> is rejected.
|
||||
/// </summary>
|
||||
/// <param name="negotiatedMaxFrameBytes">The gateway-negotiated maximum, or 0 for "keep default".</param>
|
||||
internal void AdoptNegotiatedMaxMessageBytes(uint negotiatedMaxFrameBytes)
|
||||
{
|
||||
if (negotiatedMaxFrameBytes == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (negotiatedMaxFrameBytes > MaxNegotiableFrameBytes)
|
||||
{
|
||||
throw new WorkerFrameProtocolException(
|
||||
WorkerFrameProtocolErrorCode.InvalidConfiguration,
|
||||
$"GatewayHello negotiated frame maximum {negotiatedMaxFrameBytes} exceeds the worker ceiling "
|
||||
+ $"of {MaxNegotiableFrameBytes} bytes.");
|
||||
}
|
||||
|
||||
MaxMessageBytes = (int)negotiatedMaxFrameBytes;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user