DriverHostState enum lives in Configuration.Enums/ rather than reusing Core.Abstractions.HostState so the Configuration project stays free of driver-runtime dependencies (it's referenced by both the Admin process and the Server process, so pulling in the driver-abstractions assembly to every Admin build would be unnecessary weight). The server-side publisher hosted service (follow-up PR 34) will translate HostStatusChangedEventArgs.NewState to this enum on every transition. No foreign key to ClusterNode — a Server may start reporting host status before its ClusterNode row exists (first-boot bootstrap), and we'd rather keep the status row than drop it. The Admin-side service that renders the dashboard will left-join on NodeId when presenting. Two indexes declared: IX_DriverHostStatus_Node drives the per-cluster drill-down (Admin UI joins ClusterNode on ClusterId to pick which NodeIds to fetch), IX_DriverHostStatus_LastSeen drives the stale-row query (now - LastSeen > threshold). EF migration AddDriverHostStatus creates the table + PK + both indexes. Model snapshot updated. SchemaComplianceTests expected-tables list extended. DriverHostStatusTests (3 new cases, category SchemaCompliance, uses the shared fixture DB): composite key allows same (host, driver) across different nodes AND same (node, host) across different drivers — both real-world cases the publisher needs to support; upsert-in-place pattern (fetch-by-composite-PK, mutate, save) produces one row not two — the pattern the publisher will use; State enum persists as string not int — reading the DB via ADO.NET returns 'Faulted' not '3'. Configuration.Tests SchemaCompliance suite: 10 pass / 0 fail (7 prior + 3 new). Configuration build clean. No Server or Admin code changes yet — publisher + /hosts page are PR 34. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
62 lines
2.8 KiB
C#
62 lines
2.8 KiB
C#
using ZB.MOM.WW.OtOpcUa.Configuration.Enums;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Configuration.Entities;
|
|
|
|
/// <summary>
|
|
/// Per-host connectivity snapshot the Server publishes for each driver's
|
|
/// <c>IHostConnectivityProbe.GetHostStatuses</c> entry. One row per
|
|
/// (<see cref="NodeId"/>, <see cref="DriverInstanceId"/>, <see cref="HostName"/>) triple —
|
|
/// a redundant 2-node cluster with one Galaxy driver reporting 3 platforms produces 6
|
|
/// rows, not 3, because each server node owns its own runtime view.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// Closes the data-layer piece of LMX follow-up #7 (per-AppEngine Admin dashboard
|
|
/// drill-down). The publisher hosted service on the Server side subscribes to every
|
|
/// registered driver's <c>OnHostStatusChanged</c> and upserts rows on transitions +
|
|
/// periodic liveness heartbeats. <see cref="LastSeenUtc"/> advances on every
|
|
/// heartbeat so the Admin UI can flag stale rows from a crashed Server.
|
|
/// </para>
|
|
/// <para>
|
|
/// No foreign-key to <see cref="ClusterNode"/> — a Server may start reporting host
|
|
/// status before its ClusterNode row exists (e.g. first-boot bootstrap), and we'd
|
|
/// rather keep the status row than drop it. The Admin-side service left-joins on
|
|
/// NodeId when presenting rows.
|
|
/// </para>
|
|
/// </remarks>
|
|
public sealed class DriverHostStatus
|
|
{
|
|
/// <summary>Server node that's running the driver.</summary>
|
|
public required string NodeId { get; set; }
|
|
|
|
/// <summary>Driver instance's stable id (matches <c>IDriver.DriverInstanceId</c>).</summary>
|
|
public required string DriverInstanceId { get; set; }
|
|
|
|
/// <summary>
|
|
/// Driver-side host identifier — Galaxy Platform / AppEngine name, Modbus
|
|
/// <c>host:port</c>, whatever the probe returns. Opaque to the Admin UI except as
|
|
/// a display string.
|
|
/// </summary>
|
|
public required string HostName { get; set; }
|
|
|
|
public DriverHostState State { get; set; } = DriverHostState.Unknown;
|
|
|
|
/// <summary>Timestamp of the last state transition (not of the most recent heartbeat).</summary>
|
|
public DateTime StateChangedUtc { get; set; }
|
|
|
|
/// <summary>
|
|
/// Advances on every publisher heartbeat — the Admin UI uses
|
|
/// <c>now - LastSeenUtc > threshold</c> to flag rows whose owning Server has
|
|
/// stopped reporting (crashed, network-partitioned, etc.), independent of
|
|
/// <see cref="State"/>.
|
|
/// </summary>
|
|
public DateTime LastSeenUtc { get; set; }
|
|
|
|
/// <summary>
|
|
/// Optional human-readable detail populated when <see cref="State"/> is
|
|
/// <see cref="DriverHostState.Faulted"/> — e.g. the exception message from the
|
|
/// driver's probe. Null for Running / Stopped / Unknown transitions.
|
|
/// </summary>
|
|
public string? Detail { get; set; }
|
|
}
|