feat(runtime,adminui): real GetDiagnostics from child health + /fleet/diagnostics consumer (A6)
DriverHostActor wraps the health publisher it hands its children in a ChildHealthLedger (last snapshot per driver id, forwarded to the real publisher), so GetDiagnostics now answers with each child's row id, authored name, last-published state, device counts (host statuses when the driver probes hosts, else one device) and last-change time — instead of Guid.Empty / "Spawned" / 0 / now. Entries are forgotten on StopChild and operator Restart. IFleetDiagnosticsClient gains its first consumer: the new /fleet/diagnostics page (node selector + ?node= query, revision, running-from-cache notice, per-driver table). FleetDiagnosticsClient logs the degrade-to-empty path at Warning. Review ref: 02/U1. Refs #731 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
using Akka.Actor;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ZB.MOM.WW.OtOpcUa.Cluster;
|
||||
using ZB.MOM.WW.OtOpcUa.Commons.Interfaces;
|
||||
@@ -13,7 +15,9 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Clients;
|
||||
/// Sends <see cref="GetDiagnostics"/>; expects a <see cref="NodeDiagnosticsSnapshot"/> reply.
|
||||
///
|
||||
/// On timeout or any other failure (peer down, GetDiagnostics handler missing) returns an
|
||||
/// empty snapshot so the UI degrades to "no data" instead of throwing.
|
||||
/// empty snapshot so the UI degrades to "no data" instead of throwing. The failure is logged at
|
||||
/// Warning, since the snapshot shape cannot carry it: an empty snapshot reads the same as a node with
|
||||
/// no drivers. Consumed by the <c>/fleet/diagnostics</c> page.
|
||||
/// </summary>
|
||||
public sealed class FleetDiagnosticsClient : IFleetDiagnosticsClient
|
||||
{
|
||||
@@ -21,14 +25,18 @@ public sealed class FleetDiagnosticsClient : IFleetDiagnosticsClient
|
||||
|
||||
private readonly ActorSystem _system;
|
||||
private readonly string _systemName;
|
||||
private readonly ILogger<FleetDiagnosticsClient> _log;
|
||||
|
||||
/// <summary>Initializes a new FleetDiagnosticsClient with the given actor system and cluster options.</summary>
|
||||
/// <param name="system">The Akka actor system.</param>
|
||||
/// <param name="options">Cluster configuration options.</param>
|
||||
public FleetDiagnosticsClient(ActorSystem system, IOptions<AkkaClusterOptions> options)
|
||||
/// <param name="log">Logger for the degraded-to-empty path; defaults to a no-op logger.</param>
|
||||
public FleetDiagnosticsClient(
|
||||
ActorSystem system, IOptions<AkkaClusterOptions> options, ILogger<FleetDiagnosticsClient>? log = null)
|
||||
{
|
||||
_system = system;
|
||||
_systemName = options.Value.SystemName;
|
||||
_log = log ?? NullLogger<FleetDiagnosticsClient>.Instance;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -42,8 +50,11 @@ public sealed class FleetDiagnosticsClient : IFleetDiagnosticsClient
|
||||
return await selection.Ask<NodeDiagnosticsSnapshot>(
|
||||
new GetDiagnostics(CorrelationId.NewId()), AskTimeout, linked.Token);
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex) when (!ct.IsCancellationRequested)
|
||||
{
|
||||
_log.LogWarning(ex,
|
||||
"Fleet diagnostics for node {NodeId} unavailable (no answer within {Timeout}s); returning an empty snapshot",
|
||||
nodeId.Value, AskTimeout.TotalSeconds);
|
||||
return new NodeDiagnosticsSnapshot(
|
||||
nodeId,
|
||||
CurrentRevision: null,
|
||||
|
||||
Reference in New Issue
Block a user