Merge remote-tracking branch 'origin/fix/wrk-21-drain-cluster'
ci / windows-x86 (push) Successful in 1m27s
ci / nightly-windev (push) Has been skipped
ci / java (push) Successful in 2m11s
ci / portable (push) Failing after 4m7s

# Conflicts:
#	archreview/2026-07-12/remediation/00-tracking.md
#	docs/MxAccessWorkerInstanceDesign.md
This commit is contained in:
Joseph Doherty
2026-08-07 07:18:58 -04:00
18 changed files with 1299 additions and 57 deletions
@@ -1,17 +1,11 @@
using Grpc.Core;
using ZB.MOM.WW.MxGateway.Contracts;
using ZB.MOM.WW.MxGateway.Contracts.Proto;
namespace ZB.MOM.WW.MxGateway.Server.Grpc;
public sealed class MxAccessGrpcRequestValidator
{
// Upper bound on a single DrainEvents request. DrainEvents is a diagnostics RPC that returns
// buffered events in one non-streaming reply, so an unbounded max_events could pack the whole
// queue into a session-killing frame. The worker independently caps each reply at its
// own MaxDrainEventsPerReply; this public bound rejects an obviously-abusive request loudly at
// the boundary. max_events = 0 is allowed and means "the worker's default batch cap".
private const uint MaxDrainEventsPerRequest = 10_000;
/// <summary>Validates an open session request.</summary>
/// <param name="request">The request to validate.</param>
public void ValidateOpenSession(OpenSessionRequest request)
@@ -78,10 +72,18 @@ public sealed class MxAccessGrpcRequestValidator
}
// The payload case now matches the kind, so command.DrainEvents is non-null here.
if (command.Kind is MxCommandKind.DrainEvents && command.DrainEvents.MaxEvents > MaxDrainEventsPerRequest)
// DrainEvents is a diagnostics RPC that returns buffered events in one non-streaming
// reply, so an unbounded max_events could pack the whole queue into a session-killing
// frame. The worker independently clamps every reply to the same shared ceiling and
// additionally caps it by serialized bytes; this public bound rejects an obviously-abusive
// request loudly at the boundary. max_events = 0 is allowed and means "the worker's
// default batch cap".
if (command.Kind is MxCommandKind.DrainEvents
&& command.DrainEvents.MaxEvents > GatewayContractInfo.MaxDrainEventsPerCommand)
{
throw InvalidArgument(
$"DrainEvents max_events ({command.DrainEvents.MaxEvents}) must not exceed {MaxDrainEventsPerRequest}; "
$"DrainEvents max_events ({command.DrainEvents.MaxEvents}) must not exceed "
+ $"{GatewayContractInfo.MaxDrainEventsPerCommand}; "
+ "use 0 to request the worker default batch cap.");
}
}