fix(communication): release the _activeStreams slot when relay ActorOf throws (review 2026-10-21 03/M-2)

This commit is contained in:
Joseph Doherty
2026-10-22 06:13:43 -04:00
parent dd60e236bd
commit 15496575bc
2 changed files with 44 additions and 3 deletions
@@ -413,10 +413,28 @@ public class SiteStreamGrpcServer : SiteStreamService.SiteStreamServiceBase
correlationId, streamKind, n, channelCapacity);
});
// ActorOf can throw when the actor system is terminating through a path that never
// set _shuttingDown (the downed-node watchdog). The _activeStreams slot registered
// above would otherwise leak against GrpcMaxConcurrentStreams forever (review
// 2026-10-21 03/M-2), so release it — and the channel — before rethrowing.
var actorSeq = Interlocked.Increment(ref _actorCounter);
var relayActor = _actorSystem!.ActorOf(
Props.Create(typeof(Actors.StreamRelayActor), correlationId, channel.Writer),
$"stream-relay-{correlationId}-{actorSeq}");
IActorRef relayActor;
try
{
relayActor = _actorSystem!.ActorOf(
Props.Create(typeof(Actors.StreamRelayActor), correlationId, channel.Writer),
$"stream-relay-{correlationId}-{actorSeq}");
}
catch (Exception ex)
{
_logger.LogWarning(ex,
"Could not create the relay actor for {Description} (correlation {CorrelationId}); releasing the stream slot.",
description, correlationId);
channel.Writer.TryComplete();
_activeStreams.TryRemove(
new KeyValuePair<string, StreamEntry>(correlationId, entry));
throw;
}
// The previous code called _streamSubscriber.Subscribe
// OUTSIDE the try block that owns relay-actor cleanup. If Subscribe threw