fix(health): evict deleted sites from the aggregator on the periodic site refresh

This commit is contained in:
Joseph Doherty
2026-07-08 16:27:38 -04:00
parent 87c7255912
commit d962c77bb7
7 changed files with 99 additions and 3 deletions
@@ -499,7 +499,12 @@ public class CentralCommunicationActor : ReceiveActor
var frozen = contacts.ToDictionary(
kvp => kvp.Key,
kvp => (IReadOnlyList<string>)kvp.Value.AsReadOnly());
return new SiteAddressCacheLoaded(frozen);
// Carry the full configured-site identifier set (not just the
// address-bearing subset in `frozen`) so the aggregator prunes only
// genuinely-deleted sites and never an addressless-but-configured one.
var knownSiteIds = sites.Select(s => s.SiteIdentifier).ToList();
return new SiteAddressCacheLoaded(frozen, knownSiteIds);
}).PipeTo(self);
}
@@ -570,6 +575,12 @@ public class CentralCommunicationActor : ReceiveActor
}
_log.Info("Site ClusterClient cache refreshed with {0} site(s)", _siteClients.Count);
// Self-healing eviction: a site deleted from configuration would otherwise
// linger in the aggregator as a permanently-offline tile (and live KPI
// sample source) forever. Prune on every refresh so it disappears within
// one refresh interval without needing a dedicated deletion event.
_serviceProvider.GetService<ICentralHealthAggregator>()?.PruneUnknownSites(msg.KnownSiteIds);
}
// TrackMessageForCleanup removed — the dicts it fed
@@ -650,7 +661,9 @@ public record RefreshSiteAddresses;
/// discipline. The producer wraps the constructed buckets with
/// <c>List&lt;T&gt;.AsReadOnly()</c> before piping to Self.
/// </summary>
internal record SiteAddressCacheLoaded(IReadOnlyDictionary<string, IReadOnlyList<string>> SiteContacts);
internal record SiteAddressCacheLoaded(
IReadOnlyDictionary<string, IReadOnlyList<string>> SiteContacts,
IReadOnlyCollection<string> KnownSiteIds);
/// <summary>
/// Notification sent to debug view subscribers when the stream is terminated