fix(communication): debug-stream teardown/failover unsubscribes via TryGet, never creates or disposes shared channels

This commit is contained in:
Joseph Doherty
2026-07-08 17:43:40 -04:00
parent 80013639ef
commit e75cd6f3d8
2 changed files with 76 additions and 5 deletions
@@ -466,8 +466,11 @@ public class DebugStreamBridgeActor : ReceiveActor, IWithTimers
// stops the StreamRelayActor for this correlation ID, rather than leaving a
// zombie relay actor until TCP RST / keepalive eventually detects the loss.
var previousEndpoint = _useNodeA ? _grpcNodeAAddress : _grpcNodeBAddress;
var previousClient = _grpcFactory.GetOrCreate(_siteIdentifier, previousEndpoint);
previousClient.Unsubscribe(_correlationId);
// TryGet, not GetOrCreate: unsubscribing a failed stream must never open a
// fresh channel (and, with (site,endpoint) keying, must never touch another
// session's healthy channel). Absent client => the channel is already gone
// and the site-side relay will be reaped by keepalive/session-lifetime.
_grpcFactory.TryGet(_siteIdentifier, previousEndpoint)?.Unsubscribe(_correlationId);
// Flip to the other node
_useNodeA = !_useNodeA;
@@ -489,9 +492,10 @@ public class DebugStreamBridgeActor : ReceiveActor, IWithTimers
_grpcCts?.Dispose();
_grpcCts = null;
var client = _grpcFactory.GetOrCreate(_siteIdentifier,
_useNodeA ? _grpcNodeAAddress : _grpcNodeBAddress);
client.Unsubscribe(_correlationId);
// TryGet, not GetOrCreate: teardown must never open a fresh channel just to
// unsubscribe. Absent client => nothing to cancel.
var endpoint = _useNodeA ? _grpcNodeAAddress : _grpcNodeBAddress;
_grpcFactory.TryGet(_siteIdentifier, endpoint)?.Unsubscribe(_correlationId);
}
private void SendUnsubscribe()