29 lines
1.3 KiB
C#
29 lines
1.3 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using ZB.MOM.WW.OtOpcUa.Configuration;
|
|
using ZB.MOM.WW.OtOpcUa.Configuration.Entities;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Admin.Services;
|
|
|
|
/// <summary>
|
|
/// Read-side service for ClusterNode rows + their cluster-scoped redundancy view. Consumed
|
|
/// by the RedundancyTab on the cluster detail page. Writes (role swap, node enable/disable)
|
|
/// are not supported here — role swap happens through the RedundancyCoordinator apply-lease
|
|
/// flow on the server side and would conflict with any direct DB mutation from Admin.
|
|
/// </summary>
|
|
public sealed class ClusterNodeService(OtOpcUaConfigDbContext db)
|
|
{
|
|
/// <summary>Stale-threshold matching <c>HostStatusService.StaleThreshold</c> — 30s of clock
|
|
/// tolerance covers a missed heartbeat plus publisher GC pauses.</summary>
|
|
public static readonly TimeSpan StaleThreshold = TimeSpan.FromSeconds(30);
|
|
|
|
public Task<List<ClusterNode>> ListByClusterAsync(string clusterId, CancellationToken ct) =>
|
|
db.ClusterNodes.AsNoTracking()
|
|
.Where(n => n.ClusterId == clusterId)
|
|
.OrderByDescending(n => n.ServiceLevelBase)
|
|
.ThenBy(n => n.NodeId)
|
|
.ToListAsync(ct);
|
|
|
|
public static bool IsStale(ClusterNode node) =>
|
|
node.LastSeenAt is null || DateTime.UtcNow - node.LastSeenAt.Value > StaleThreshold;
|
|
}
|