61193629b6
v2-ci / build (push) Failing after 36s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
Both bugs surfaced only on split-role deployments (the MAIN cluster's admin-only nodes), where the AdminUI runs without the driver role. - Test Connect returned "No probe registered" for every driver: the IDriverProbe set was registered only under the driver role, but the admin-operations singleton that consumes it is pinned to admin. Extract AddOtOpcUaDriverProbes() (idempotent via TryAddEnumerable) and call it in the hasAdmin path too. - Live driver-status/alerts/script-log panels showed "SignalR error: Connection refused": these Blazor Server components opened a HubConnection to their own hub via the browser's public URL, which server-side code can't reach behind Traefik (host :9200 -> container :9000). Read the in-process source directly instead -- DriverStatus via IDriverStatusSnapshotStore.SnapshotChanged, Alerts/ScriptLog via a new IInProcessBroadcaster<T>. Fleet status was unaffected (reads DB/ActorSystem). Adds unit tests for probe registration, the snapshot-store event, and the broadcaster.
57 lines
2.5 KiB
C#
57 lines
2.5 KiB
C#
using Akka.Actor;
|
|
using Akka.Cluster.Tools.PublishSubscribe;
|
|
using Akka.Event;
|
|
using Microsoft.AspNetCore.SignalR;
|
|
using ZB.MOM.WW.OtOpcUa.Commons.Messages.Logging;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Hubs;
|
|
|
|
/// <summary>
|
|
/// Akka actor that subscribes to the <c>script-logs</c> DistributedPubSub topic and forwards each
|
|
/// <see cref="ScriptLogEntry"/> to every SignalR client connected to <see cref="ScriptLogHub"/>.
|
|
/// </summary>
|
|
public sealed class ScriptLogSignalRBridge : ReceiveActor
|
|
{
|
|
public const string TopicName = "script-logs";
|
|
|
|
private readonly IHubContext<ScriptLogHub> _hub;
|
|
private readonly IInProcessBroadcaster<ScriptLogEntry> _broadcaster;
|
|
private readonly ILoggingAdapter _log = Context.GetLogger();
|
|
|
|
/// <summary>Creates a Props instance for the ScriptLogSignalRBridge.</summary>
|
|
/// <param name="hub">The SignalR hub context for sending messages to clients.</param>
|
|
/// <param name="broadcaster">In-process fan-out read directly by the Blazor Server Script log page.</param>
|
|
public static Props Props(IHubContext<ScriptLogHub> hub, IInProcessBroadcaster<ScriptLogEntry> broadcaster) =>
|
|
Akka.Actor.Props.Create(() => new ScriptLogSignalRBridge(hub, broadcaster));
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="ScriptLogSignalRBridge"/> class.</summary>
|
|
/// <param name="hub">The SignalR hub context for sending messages to clients.</param>
|
|
/// <param name="broadcaster">In-process fan-out read directly by the Blazor Server Script log page.</param>
|
|
public ScriptLogSignalRBridge(IHubContext<ScriptLogHub> hub, IInProcessBroadcaster<ScriptLogEntry> broadcaster)
|
|
{
|
|
_hub = hub;
|
|
_broadcaster = broadcaster;
|
|
ReceiveAsync<ScriptLogEntry>(ForwardAsync);
|
|
Receive<SubscribeAck>(_ => { /* DPS confirmation */ });
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
protected override void PreStart() =>
|
|
DistributedPubSub.Get(Context.System).Mediator.Tell(new Subscribe(TopicName, Self));
|
|
|
|
private async Task ForwardAsync(ScriptLogEntry msg)
|
|
{
|
|
// In-process fan-out first — this is what the Blazor Server Script log page reads. The hub
|
|
// push is kept for any out-of-process (e.g. WASM) SignalR client.
|
|
_broadcaster.Publish(msg);
|
|
try
|
|
{
|
|
await _hub.Clients.All.SendAsync(ScriptLogHub.MethodName, msg);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_log.Warning(ex, "ScriptLogSignalRBridge: SignalR push failed for {ScriptId}", msg.ScriptId);
|
|
}
|
|
}
|
|
}
|