fix(communication): site-address load guard cannot wedge on an unexpected fault; lifecycle-cancelled loads log at Debug (review 2026-10-21 03/M-1 follow-up)

This commit is contained in:
Joseph Doherty
2026-10-22 08:29:02 -04:00
parent 4456a04e81
commit e0ebebac11
2 changed files with 69 additions and 7 deletions
@@ -116,4 +116,42 @@ public class CentralCommunicationActorAddressRefreshTests : TestKit
transport.DidNotReceive().ReconcileSites(
Arg.Is<SiteAddressCacheLoaded>(c => c.GrpcContacts.ContainsKey("site-old")));
}
/// <summary>Verifies that an unexpected Status.Failure releases the overlap guard so later refreshes still load.</summary>
[Fact]
public void UnexpectedStatusFailure_ReleasesTheOverlapGuard()
{
var calls = 0;
var repo = Substitute.For<ISiteRepository>();
repo.GetAllSitesAsync(Arg.Any<CancellationToken>()).Returns(_ =>
{
Interlocked.Increment(ref calls);
return new TaskCompletionSource<IReadOnlyList<Site>>().Task; // never completes
});
var (actor, _) = CreateActor(repo);
AwaitCondition(() => Volatile.Read(ref calls) == 1, TimeSpan.FromSeconds(3));
actor.Tell(new Status.Failure(new InvalidOperationException("unexpected pipe fault")));
actor.Tell(new RefreshSiteAddresses());
AwaitCondition(() => Volatile.Read(ref calls) == 2, TimeSpan.FromSeconds(3));
}
/// <summary>Verifies that a load cancelled by the actor lifecycle (stop/restart) is not logged as a Warning.</summary>
[Fact]
public void LoadCancelledByActorLifecycle_IsNotAWarning()
{
var repo = Substitute.For<ISiteRepository>();
repo.GetAllSitesAsync(Arg.Any<CancellationToken>()).Returns(new List<Site>());
var (actor, _) = CreateActor(repo);
// A previous incarnation's load, cancelled by its PostStop, lands on the restarted actor.
EventFilter.Warning(contains: "site addresses").Expect(0, TimeSpan.FromSeconds(1), () =>
actor.Tell(new SiteAddressLoadFailed(1, new OperationCanceledException(), null, ActorStopping: true)));
// A genuine DB failure still warns.
EventFilter.Warning(contains: "site addresses").ExpectOne(TimeSpan.FromSeconds(3), () =>
actor.Tell(new SiteAddressLoadFailed(2, new InvalidOperationException("db down"), null)));
}
}