fix(dotnet-client): no ack retry, caller-owned channels, safe session dispose, typed diagnostics, AttachSession

This commit is contained in:
Joseph Doherty
2026-10-22 06:09:25 -04:00
parent 488649ce99
commit 6f0b408833
6 changed files with 495 additions and 27 deletions
+24
View File
@@ -137,6 +137,30 @@ gateway's own sentinel observable. Normal events pass through with
`IsReplayGap == false` and `ReplayGap == null`. The gap is only ever produced by
`StreamEvents`; the diagnostic drain path never emits it. If you already consume
the raw `StreamEventsAsync` (or the client-level stream), the
### Caller-owned channels, resuming sessions, diagnostics
`MxGatewayClient.Create(GrpcChannel, MxGatewayClientOptions)` and
`GalaxyRepositoryClient.Create(GrpcChannel, MxGatewayClientOptions)` build a
client over a channel the caller created (shared channel, custom handler or
TLS). The client never disposes a caller-owned channel; `Create(options)` still
creates and owns its own channel.
`MxGatewayClient.AttachSession(sessionId)` returns an `MxGatewaySession` bound
to an existing session id without calling OpenSession, so a restarted process
can resume `StreamEventsAsync(afterWorkerSequence)`. The gateway only allows the
API key that opened the session to attach; any other key gets `PermissionDenied`.
The attached session's `OpenSessionReply` carries only the session id.
`MxGatewaySession` has typed diagnostics: `PingAsync`, `GetSessionStateAsync`,
`GetWorkerInfoAsync`, and `DrainEventsAsync` (removes queued events from the
worker; call until empty). `DisposeAsync` closes the session best-effort and does
not throw when the gateway is unreachable or the client is already disposed.
Retry applies only to idempotent calls (`CloseSessionRawAsync`, ping,
session-state and worker-info commands, Galaxy reads). `AcknowledgeAlarmAsync`
is never retried because it is a non-idempotent operator write that re-sends the
operator password and can double-acknowledge in the Historian.
`AsStreamItemsAsync()` extension projects any `IAsyncEnumerable<MxEvent>` into
the same `MxEventStreamItem` surface.