feat: replace site registration with database-driven site addressing

Central now resolves site Akka remoting addresses from the Sites DB table
(NodeAAddress/NodeBAddress) instead of relying on runtime RegisterSite
messages. Eliminates the race condition where sites starting before central
had their registration dead-lettered. Addresses are cached in
CentralCommunicationActor with 60s periodic refresh and on-demand refresh
when sites are added/edited/deleted via UI or CLI.
This commit is contained in:
Joseph Doherty
2026-03-17 23:13:10 -04:00
parent eb8d5ca2c0
commit 9e97c1acd2
21 changed files with 1641 additions and 92 deletions

View File

@@ -169,7 +169,7 @@ akka {{
private void RegisterCentralActors()
{
var centralCommActor = _actorSystem!.ActorOf(
Props.Create(() => new CentralCommunicationActor()),
Props.Create(() => new CentralCommunicationActor(_serviceProvider)),
"central-communication");
// Wire up the CommunicationService with the actor reference
@@ -264,13 +264,8 @@ akka {{
var siteCommActor = _actorSystem.ActorSelection("/user/site-communication");
siteCommActor.Tell(new RegisterCentralPath(_communicationOptions.CentralActorPath));
// Also register this site with Central so it knows our address
var centralSelection = _actorSystem.ActorSelection(_communicationOptions.CentralActorPath);
var localSiteCommPath = $"akka.tcp://scadalink@{_nodeOptions.NodeHostname}:{_nodeOptions.RemotingPort}/user/site-communication";
centralSelection.Tell(new RegisterSite(_nodeOptions.SiteId!, localSiteCommPath));
_logger.LogInformation(
"Registered with Central at {CentralPath} as site {SiteId}",
"Configured central heartbeat path at {CentralPath} for site {SiteId}",
_communicationOptions.CentralActorPath, _nodeOptions.SiteId);
}
}

View File

@@ -83,11 +83,14 @@
<script src="/_framework/blazor.web.js"></script>
<script>
// Reconnection overlay for failover behavior
if (Blazor) {
Blazor.addEventListener('enhancedload', () => {
document.getElementById('reconnect-modal').style.display = 'none';
});
}
// Blazor object is available after blazor.web.js initializes
document.addEventListener('DOMContentLoaded', () => {
if (typeof Blazor !== 'undefined') {
Blazor.addEventListener('enhancedload', () => {
document.getElementById('reconnect-modal').style.display = 'none';
});
}
});
</script>
<script src="/lib/bootstrap/js/bootstrap.bundle.min.js"></script>
</body>

View File

@@ -130,6 +130,7 @@ try
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
app.MapStaticAssets();
app.MapCentralUI<ScadaLink.Host.Components.App>();
app.MapInboundAPI();
await app.RunAsync();