feat(lmxproxy): add Connected Since and Reconnect Count to status page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,12 @@ namespace ZB.MOM.WW.LmxProxy.Host.Domain
|
|||||||
/// <summary>Gets the current connection state.</summary>
|
/// <summary>Gets the current connection state.</summary>
|
||||||
ConnectionState ConnectionState { get; }
|
ConnectionState ConnectionState { get; }
|
||||||
|
|
||||||
|
/// <summary>Gets the UTC time when the current connection was established.</summary>
|
||||||
|
DateTime ConnectedSince { get; }
|
||||||
|
|
||||||
|
/// <summary>Gets the number of times the client has reconnected since startup.</summary>
|
||||||
|
int ReconnectCount { get; }
|
||||||
|
|
||||||
/// <summary>Occurs when the connection state changes.</summary>
|
/// <summary>Occurs when the connection state changes.</summary>
|
||||||
event EventHandler<ConnectionStateChangedEventArgs> ConnectionStateChanged;
|
event EventHandler<ConnectionStateChangedEventArgs> ConnectionStateChanged;
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,9 @@ namespace ZB.MOM.WW.LmxProxy.Host.MxAccess
|
|||||||
get { lock (_lock) { return _connectedSince; } }
|
get { lock (_lock) { return _connectedSince; } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the number of times the client has reconnected since startup.</summary>
|
||||||
|
public int ReconnectCount => _reconnectCount;
|
||||||
|
|
||||||
// ── Internal synchronous methods ──────────
|
// ── Internal synchronous methods ──────────
|
||||||
|
|
||||||
private void ConnectInternal()
|
private void ConnectInternal()
|
||||||
@@ -278,7 +281,8 @@ namespace ZB.MOM.WW.LmxProxy.Host.MxAccess
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ConnectAsync(ct);
|
await ConnectAsync(ct);
|
||||||
Log.Information("Reconnected to MxAccess successfully");
|
Interlocked.Increment(ref _reconnectCount);
|
||||||
|
Log.Information("Reconnected to MxAccess successfully (reconnect #{Count})", _reconnectCount);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ namespace ZB.MOM.WW.LmxProxy.Host.MxAccess
|
|||||||
// Probe state — updated by OnDataChange callback, read by monitor loop
|
// Probe state — updated by OnDataChange callback, read by monitor loop
|
||||||
private DateTime _lastProbeValueTime;
|
private DateTime _lastProbeValueTime;
|
||||||
|
|
||||||
|
// Reconnect counter
|
||||||
|
private int _reconnectCount;
|
||||||
|
|
||||||
// Stored subscriptions for reconnect replay
|
// Stored subscriptions for reconnect replay
|
||||||
private readonly Dictionary<string, Action<string, Vtq>> _storedSubscriptions
|
private readonly Dictionary<string, Action<string, Vtq>> _storedSubscriptions
|
||||||
= new Dictionary<string, Action<string, Vtq>>(StringComparer.OrdinalIgnoreCase);
|
= new Dictionary<string, Action<string, Vtq>>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ namespace ZB.MOM.WW.LmxProxy.Host.Status
|
|||||||
public string State { get; set; } = "";
|
public string State { get; set; } = "";
|
||||||
public string NodeName { get; set; } = "";
|
public string NodeName { get; set; } = "";
|
||||||
public string GalaxyName { get; set; } = "";
|
public string GalaxyName { get; set; } = "";
|
||||||
|
public DateTime? ConnectedSince { get; set; }
|
||||||
|
public int ReconnectCount { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SubscriptionStatus
|
public class SubscriptionStatus
|
||||||
|
|||||||
@@ -83,7 +83,9 @@ namespace ZB.MOM.WW.LmxProxy.Host.Status
|
|||||||
statusData.Connection = new ConnectionStatus
|
statusData.Connection = new ConnectionStatus
|
||||||
{
|
{
|
||||||
IsConnected = _scadaClient.IsConnected,
|
IsConnected = _scadaClient.IsConnected,
|
||||||
State = _scadaClient.ConnectionState.ToString()
|
State = _scadaClient.ConnectionState.ToString(),
|
||||||
|
ConnectedSince = _scadaClient.IsConnected ? _scadaClient.ConnectedSince : (DateTime?)null,
|
||||||
|
ReconnectCount = _scadaClient.ReconnectCount
|
||||||
};
|
};
|
||||||
|
|
||||||
// Subscription stats
|
// Subscription stats
|
||||||
@@ -180,6 +182,10 @@ namespace ZB.MOM.WW.LmxProxy.Host.Status
|
|||||||
sb.AppendLine(" <h3>Connection</h3>");
|
sb.AppendLine(" <h3>Connection</h3>");
|
||||||
sb.AppendLine($" <p><strong>Connected:</strong> {statusData.Connection.IsConnected}</p>");
|
sb.AppendLine($" <p><strong>Connected:</strong> {statusData.Connection.IsConnected}</p>");
|
||||||
sb.AppendLine($" <p><strong>State:</strong> {statusData.Connection.State}</p>");
|
sb.AppendLine($" <p><strong>State:</strong> {statusData.Connection.State}</p>");
|
||||||
|
if (statusData.Connection.ConnectedSince.HasValue)
|
||||||
|
sb.AppendLine($" <p><strong>Connected Since:</strong> {statusData.Connection.ConnectedSince.Value:yyyy-MM-dd HH:mm:ss} UTC</p>");
|
||||||
|
if (statusData.Connection.ReconnectCount > 0)
|
||||||
|
sb.AppendLine($" <p><strong>Reconnects:</strong> {statusData.Connection.ReconnectCount}</p>");
|
||||||
if (!string.IsNullOrEmpty(statusData.Connection.NodeName))
|
if (!string.IsNullOrEmpty(statusData.Connection.NodeName))
|
||||||
sb.AppendLine($" <p><strong>Node:</strong> {statusData.Connection.NodeName}</p>");
|
sb.AppendLine($" <p><strong>Node:</strong> {statusData.Connection.NodeName}</p>");
|
||||||
if (!string.IsNullOrEmpty(statusData.Connection.GalaxyName))
|
if (!string.IsNullOrEmpty(statusData.Connection.GalaxyName))
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ namespace ZB.MOM.WW.LmxProxy.Host.Tests.Health
|
|||||||
{
|
{
|
||||||
public bool IsConnected { get; set; } = true;
|
public bool IsConnected { get; set; } = true;
|
||||||
public ConnectionState ConnectionState { get; set; } = ConnectionState.Connected;
|
public ConnectionState ConnectionState { get; set; } = ConnectionState.Connected;
|
||||||
|
public DateTime ConnectedSince => DateTime.UtcNow;
|
||||||
|
public int ReconnectCount => 0;
|
||||||
public event EventHandler<ConnectionStateChangedEventArgs>? ConnectionStateChanged;
|
public event EventHandler<ConnectionStateChangedEventArgs>? ConnectionStateChanged;
|
||||||
public Task ConnectAsync(CancellationToken ct = default) => Task.CompletedTask;
|
public Task ConnectAsync(CancellationToken ct = default) => Task.CompletedTask;
|
||||||
public Task DisconnectAsync(CancellationToken ct = default) => Task.CompletedTask;
|
public Task DisconnectAsync(CancellationToken ct = default) => Task.CompletedTask;
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ namespace ZB.MOM.WW.LmxProxy.Host.Tests.Status
|
|||||||
{
|
{
|
||||||
public bool IsConnected { get; set; } = true;
|
public bool IsConnected { get; set; } = true;
|
||||||
public ConnectionState ConnectionState { get; set; } = ConnectionState.Connected;
|
public ConnectionState ConnectionState { get; set; } = ConnectionState.Connected;
|
||||||
|
public DateTime ConnectedSince => DateTime.UtcNow;
|
||||||
|
public int ReconnectCount => 0;
|
||||||
public event EventHandler<ConnectionStateChangedEventArgs>? ConnectionStateChanged;
|
public event EventHandler<ConnectionStateChangedEventArgs>? ConnectionStateChanged;
|
||||||
public Task ConnectAsync(CancellationToken ct = default) => Task.CompletedTask;
|
public Task ConnectAsync(CancellationToken ct = default) => Task.CompletedTask;
|
||||||
public Task DisconnectAsync(CancellationToken ct = default) => Task.CompletedTask;
|
public Task DisconnectAsync(CancellationToken ct = default) => Task.CompletedTask;
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ namespace ZB.MOM.WW.LmxProxy.Host.Tests.Subscriptions
|
|||||||
{
|
{
|
||||||
public bool IsConnected => true;
|
public bool IsConnected => true;
|
||||||
public ConnectionState ConnectionState => ConnectionState.Connected;
|
public ConnectionState ConnectionState => ConnectionState.Connected;
|
||||||
|
public DateTime ConnectedSince => DateTime.UtcNow;
|
||||||
|
public int ReconnectCount => 0;
|
||||||
public event EventHandler<ConnectionStateChangedEventArgs>? ConnectionStateChanged;
|
public event EventHandler<ConnectionStateChangedEventArgs>? ConnectionStateChanged;
|
||||||
public Task ConnectAsync(CancellationToken ct = default) => Task.CompletedTask;
|
public Task ConnectAsync(CancellationToken ct = default) => Task.CompletedTask;
|
||||||
public Task DisconnectAsync(CancellationToken ct = default) => Task.CompletedTask;
|
public Task DisconnectAsync(CancellationToken ct = default) => Task.CompletedTask;
|
||||||
|
|||||||
Reference in New Issue
Block a user