feat(grpc-events): handle-capture cycle — event-row gap proven NOT a client payload issue
Extends the instrument-grpc rewrite to log string (strHandle) + uint (uiHandle / queryRequestType) params, not just byte[], and captures our SDK's live v8 openParameters for a byte-diff against the native. Result of the exhaustive comparison (all live-confirmed via the opt-in EventReadDiagnostic test): - StartEventQuery request: byte-identical to the native (v6 layout) - v8 OpenConnection openParameters: byte-identical to the native (302B) once ClientNodeName matches — every control byte/ConnectionType/token/ShardId - handle usage identical: ExchangeKey->contextKey, registration->storage GUID (strHandle), query->client uint (uiHandle); handles valid (RTag/EnsT=True) - queryRequestType=3, registration order, gzip metadata header — all match - window has events (native returns 50 now); eventCount not it Every observable client-side byte matches the native, yet the server scopes 0 events to our connection. The event RPCs succeed over our transport and return a valid EMPTY result (not a transport error), so this is a connection/server-level difference (session affinity tied to the native Grpc.Core HTTP/2 connection or a connection identity used to scope events) — invisible to and unfixable by client payload matching. Needs server-side insight, not more wire RE. Added opt-in diagnostics (RegistrationDiag, LastResultBufferHex, LastEventOpenRequestHex). 326/326 offline; gated test still pins the no-row throw. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B6mcaT2PjRFKcogzp9UkfC
This commit is contained in:
@@ -306,7 +306,7 @@ internal sealed class HistorianGrpcEventOrchestrator
|
||||
}
|
||||
|
||||
uint queryHandle = startResponse.UiQueryHandle;
|
||||
RegistrationDiag += $"QH={queryHandle} clientH={session.ClientHandle} SEQresp={Convert.ToHexString(startResponse.BtResonse?.ToByteArray() ?? [])}; ";
|
||||
RegistrationDiag += $"QH={queryHandle} clientH={session.ClientHandle} strH={session.StringHandle}; ";
|
||||
try
|
||||
{
|
||||
List<HistorianEvent> events = [];
|
||||
|
||||
@@ -21,6 +21,9 @@ namespace AVEVA.Historian.Client.Grpc;
|
||||
/// </summary>
|
||||
internal static class HistorianGrpcHandshake
|
||||
{
|
||||
/// <summary>Diagnostic: hex of the most recent v8 event-connection OpenConnection request.</summary>
|
||||
internal static string LastEventOpenRequestHex { get; private set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The handles produced by a successful OpenConnection. <see cref="ClientHandle"/> is the
|
||||
/// transient <c>uint</c> session token used by StartQuery/GetSystemParameter and the other
|
||||
@@ -121,6 +124,7 @@ internal static class HistorianGrpcHandshake
|
||||
byte[] open2Request = eventConnection
|
||||
? HistorianNativeHandshake.BuildEventOpenConnectionVersion8Request(contextKey, options.UserName, eventToken)
|
||||
: HistorianNativeHandshake.BuildOpenConnection3Request(options.Host, contextKey, connectionMode);
|
||||
if (eventConnection) { LastEventOpenRequestHex = Convert.ToHexString(open2Request); }
|
||||
|
||||
GrpcHistory.OpenConnectionResponse open2 = historyClient.OpenConnection(
|
||||
new GrpcHistory.OpenConnectionRequest { BtConnectionRequest = ByteString.CopyFrom(open2Request) },
|
||||
|
||||
Reference in New Issue
Block a user