fix(r2-10): in-process resilience status store
This commit is contained in:
@@ -28,6 +28,7 @@ public static class HubServiceCollectionExtensions
|
||||
public static IServiceCollection AddOtOpcUaDriverStatusServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IDriverStatusSnapshotStore, InMemoryDriverStatusSnapshotStore>();
|
||||
services.AddSingleton<IDriverResilienceStatusStore, InMemoryDriverResilienceStatusStore>();
|
||||
services.AddSingleton(typeof(IInProcessBroadcaster<>), typeof(InProcessBroadcaster<>));
|
||||
return services;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using ZB.MOM.WW.OtOpcUa.Commons.Messages.Drivers;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Hubs;
|
||||
|
||||
/// <summary>
|
||||
/// Singleton last-snapshot-per-<c>(instance, host)</c> cache of driver resilience status
|
||||
/// (breaker open / consecutive failures / in-flight depth). Populated by
|
||||
/// <c>DriverResilienceStatusBridge</c> as it forwards <c>driver-resilience-status</c> DPS
|
||||
/// messages; read in-process by the driver status panel's resilience section via
|
||||
/// <see cref="SnapshotChanged"/> + <see cref="GetForInstance"/>. Mirrors
|
||||
/// <see cref="IDriverStatusSnapshotStore"/> — the panel reads this singleton directly instead of
|
||||
/// opening a self-targeted SignalR connection (which a server-side Blazor component cannot reach
|
||||
/// behind a reverse proxy).
|
||||
/// </summary>
|
||||
public interface IDriverResilienceStatusStore
|
||||
{
|
||||
/// <summary>Stores or replaces the last-known resilience snapshot for a <c>(instance, host)</c> pair.</summary>
|
||||
/// <param name="snapshot">The resilience status snapshot to store.</param>
|
||||
void Upsert(DriverResilienceStatusChanged snapshot);
|
||||
|
||||
/// <summary>Returns every stored host snapshot for one driver instance (empty if none).</summary>
|
||||
/// <param name="driverInstanceId">The driver instance's stable logical ID.</param>
|
||||
/// <returns>The per-host resilience snapshots for that instance.</returns>
|
||||
IReadOnlyList<DriverResilienceStatusChanged> GetForInstance(string driverInstanceId);
|
||||
|
||||
/// <summary>Returns a point-in-time snapshot of every tracked <c>(instance, host)</c> pair.</summary>
|
||||
/// <returns>A read-only collection of the last-known resilience snapshot for each pair.</returns>
|
||||
IReadOnlyCollection<DriverResilienceStatusChanged> GetAll();
|
||||
|
||||
/// <summary>
|
||||
/// Raised after every <see cref="Upsert"/> with the just-stored snapshot. Lets the Blazor Server
|
||||
/// driver status panel receive live updates by reading this singleton directly. Handlers run on
|
||||
/// the caller's thread (the bridge actor), so subscribers must marshal to their own sync context.
|
||||
/// </summary>
|
||||
event Action<DriverResilienceStatusChanged>? SnapshotChanged;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Concurrent;
|
||||
using ZB.MOM.WW.OtOpcUa.Commons.Messages.Drivers;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Hubs;
|
||||
|
||||
/// <summary>
|
||||
/// Thread-safe in-memory implementation of <see cref="IDriverResilienceStatusStore"/>.
|
||||
/// Keyed by <c>(DriverInstanceId, HostName)</c>; last write wins.
|
||||
/// </summary>
|
||||
public sealed class InMemoryDriverResilienceStatusStore : IDriverResilienceStatusStore
|
||||
{
|
||||
private readonly ConcurrentDictionary<(string Instance, string Host), DriverResilienceStatusChanged> _byPair = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public event Action<DriverResilienceStatusChanged>? SnapshotChanged;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Upsert(DriverResilienceStatusChanged snapshot)
|
||||
{
|
||||
_byPair[(snapshot.DriverInstanceId, snapshot.HostName)] = snapshot;
|
||||
// Capture-then-invoke so a concurrent unsubscribe can't null the delegate mid-raise.
|
||||
SnapshotChanged?.Invoke(snapshot);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<DriverResilienceStatusChanged> GetForInstance(string driverInstanceId) =>
|
||||
_byPair.Values
|
||||
.Where(s => string.Equals(s.DriverInstanceId, driverInstanceId, StringComparison.Ordinal))
|
||||
.ToList();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyCollection<DriverResilienceStatusChanged> GetAll() => _byPair.Values.ToArray();
|
||||
}
|
||||
Reference in New Issue
Block a user