fix(r2-10): driver-resilience-status DPS bridge

This commit is contained in:
Joseph Doherty
2026-07-13 10:44:44 -04:00
parent 99ce5b401e
commit 38c059dae7
3 changed files with 48 additions and 1 deletions
@@ -0,0 +1,39 @@
using Akka.Actor;
using Akka.Cluster.Tools.PublishSubscribe;
using ZB.MOM.WW.OtOpcUa.Commons.Messages.Drivers;
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Hubs;
/// <summary>
/// Akka actor that subscribes to the <c>driver-resilience-status</c> DistributedPubSub topic and
/// upserts every <see cref="DriverResilienceStatusChanged"/> snapshot into the in-process
/// <see cref="IDriverResilienceStatusStore"/>. The driver status panel's resilience section reads
/// that store directly (per the house ban on server-side self-targeted SignalR connections), so —
/// unlike <see cref="DriverStatusSignalRBridge"/> — there is no SignalR hub here; resilience has no
/// browser-JS consumer. Spawned per admin-role node by <c>WithOtOpcUaSignalRBridges</c>.
/// </summary>
public sealed class DriverResilienceStatusBridge : ReceiveActor
{
public const string TopicName = DriverResilienceStatusChanged.TopicName;
private readonly IDriverResilienceStatusStore _store;
/// <summary>Creates actor props for a <see cref="DriverResilienceStatusBridge"/>.</summary>
/// <param name="store">Resilience status store updated on every forwarded snapshot.</param>
/// <returns>An Akka.NET <see cref="Props"/> instance for spawning the bridge actor.</returns>
public static Props Props(IDriverResilienceStatusStore store) =>
Akka.Actor.Props.Create(() => new DriverResilienceStatusBridge(store));
/// <summary>Initializes a new instance of <see cref="DriverResilienceStatusBridge"/>.</summary>
/// <param name="store">Resilience status store updated on every forwarded snapshot.</param>
public DriverResilienceStatusBridge(IDriverResilienceStatusStore store)
{
_store = store;
Receive<DriverResilienceStatusChanged>(msg => _store.Upsert(msg));
Receive<SubscribeAck>(_ => { /* DPS confirmation */ });
}
/// <inheritdoc />
protected override void PreStart() =>
DistributedPubSub.Get(Context.System).Mediator.Tell(new Subscribe(TopicName, Self));
}
@@ -11,6 +11,7 @@ public static class HubServiceCollectionExtensions
public const string AlertSignalRBridgeName = "alert-signalr-bridge";
public const string ScriptLogSignalRBridgeName = "script-log-signalr-bridge";
public const string DriverStatusSignalRBridgeName = "driver-status-signalr-bridge";
public const string DriverResilienceStatusBridgeName = "driver-resilience-status-bridge";
/// <summary>
/// Registers the in-process live-push services the AdminUI's Blazor Server panels read
@@ -71,6 +72,12 @@ public static class HubServiceCollectionExtensions
var driverStatusStore = resolver.GetService<IDriverStatusSnapshotStore>();
var driverStatusBridge = system.ActorOf(DriverStatusSignalRBridge.Props(driverStatusHub, driverStatusStore), DriverStatusSignalRBridgeName);
registry.Register<DriverStatusSignalRBridgeKey>(driverStatusBridge);
// Resilience-status bridge: DPS topic -> in-process store (no SignalR hub — the panel reads
// the store directly, and resilience has no browser-JS consumer).
var resilienceStore = resolver.GetService<IDriverResilienceStatusStore>();
var resilienceBridge = system.ActorOf(DriverResilienceStatusBridge.Props(resilienceStore), DriverResilienceStatusBridgeName);
registry.Register<DriverResilienceStatusBridgeKey>(resilienceBridge);
});
return builder;
}
@@ -81,3 +88,4 @@ public sealed class FleetStatusSignalRBridgeKey { }
public sealed class AlertSignalRBridgeKey { }
public sealed class ScriptLogSignalRBridgeKey { }
public sealed class DriverStatusSignalRBridgeKey { }
public sealed class DriverResilienceStatusBridgeKey { }