fix: HardwareDataBroadcaster幂等Discover与静默异常增强(失败计数+通道暂停+日志)
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
using Common.Attributes;
|
using Common.Attributes;
|
||||||
using DeviceCommand.Base;
|
using DeviceCommand.Base;
|
||||||
|
using Logger;
|
||||||
using Model.Models;
|
using Model.Models;
|
||||||
using Prism.Events;
|
using Prism.Events;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
@@ -41,6 +43,18 @@ namespace UIShare.GlobalVariable
|
|||||||
private CancellationTokenSource? _cts;
|
private CancellationTokenSource? _cts;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
|
/// <summary>是否已完成过至少一次 Discover(幂等标记,避免多作用域重复调用时 Clear + 重扫)</summary>
|
||||||
|
private bool _discovered;
|
||||||
|
|
||||||
|
/// <summary>连续失败次数达到此阈值后,暂停该通道采样并发布报警</summary>
|
||||||
|
private const int FailureThreshold = 5;
|
||||||
|
|
||||||
|
/// <summary>每通道连续失败计数(key = fingerprint + "|" + methodName)</summary>
|
||||||
|
private readonly ConcurrentDictionary<string, int> _failureCounts = new();
|
||||||
|
|
||||||
|
/// <summary>已因连续失败而被暂停的通道(key 同上)</summary>
|
||||||
|
private readonly ConcurrentDictionary<string, bool> _suspendedChannels = new();
|
||||||
|
|
||||||
/// <summary>采样间隔(默认 1000ms)</summary>
|
/// <summary>采样间隔(默认 1000ms)</summary>
|
||||||
public TimeSpan SampleInterval
|
public TimeSpan SampleInterval
|
||||||
{
|
{
|
||||||
@@ -89,9 +103,12 @@ namespace UIShare.GlobalVariable
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 扫描 GlobalInfo.HardwarePool 中所有已创建的物理设备,
|
/// 扫描 GlobalInfo.HardwarePool 中所有已创建的物理设备,
|
||||||
/// 反查可监测方法并编译为委托。每个指纹只注册一次,反射只执行一次。
|
/// 反查可监测方法并编译为委托。每个指纹只注册一次,反射只执行一次。
|
||||||
|
/// <para>幂等:首次调用后再次调用不会 Clear 重扫,避免多作用域重复 Discover 导致短暂采样中断。</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Discover()
|
public void Discover()
|
||||||
{
|
{
|
||||||
|
if (_discovered) return;
|
||||||
|
_discovered = true;
|
||||||
_registeredMethods.Clear();
|
_registeredMethods.Clear();
|
||||||
|
|
||||||
foreach (var poolEntry in _globalInfo.HardwarePool)
|
foreach (var poolEntry in _globalInfo.HardwarePool)
|
||||||
@@ -157,6 +174,11 @@ namespace UIShare.GlobalVariable
|
|||||||
|
|
||||||
foreach (var entry in _registeredMethods)
|
foreach (var entry in _registeredMethods)
|
||||||
{
|
{
|
||||||
|
string channelKey = entry.Fingerprint + "|" + entry.MethodName;
|
||||||
|
|
||||||
|
// 已暂停的通道跳过采样
|
||||||
|
if (_suspendedChannels.ContainsKey(channelKey)) continue;
|
||||||
|
|
||||||
// fire-and-forget:每个通道独立采样,完成后自行广播
|
// fire-and-forget:每个通道独立采样,完成后自行广播
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@@ -167,6 +189,9 @@ namespace UIShare.GlobalVariable
|
|||||||
|
|
||||||
if (!double.TryParse(raw, out double value)) return;
|
if (!double.TryParse(raw, out double value)) return;
|
||||||
|
|
||||||
|
// 采样成功,重置失败计数
|
||||||
|
_failureCounts.TryRemove(channelKey, out _);
|
||||||
|
|
||||||
// 向所有引用该物理设备的作用域分别广播
|
// 向所有引用该物理设备的作用域分别广播
|
||||||
var scopes = GetScopesForFingerprint(entry.Fingerprint);
|
var scopes = GetScopesForFingerprint(entry.Fingerprint);
|
||||||
foreach (var scope in scopes)
|
foreach (var scope in scopes)
|
||||||
@@ -188,9 +213,24 @@ namespace UIShare.GlobalVariable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// 单个通道故障不干扰其他通道
|
int count = _failureCounts.AddOrUpdate(channelKey, 1, (_, c) => c + 1);
|
||||||
|
LoggerHelper.Warn($"采样通道 [{entry.Fingerprint}/{entry.MethodName}] 第 {count} 次失败: {ex.Message}");
|
||||||
|
|
||||||
|
if (count >= FailureThreshold)
|
||||||
|
{
|
||||||
|
_suspendedChannels.TryAdd(channelKey, true);
|
||||||
|
LoggerHelper.Error($"采样通道 [{entry.Fingerprint}/{entry.MethodName}] 连续失败 {count} 次,已暂停采样");
|
||||||
|
|
||||||
|
// 向所有引用该设备的作用域发布报警
|
||||||
|
var scopes = GetScopesForFingerprint(entry.Fingerprint);
|
||||||
|
foreach (var scope in scopes)
|
||||||
|
{
|
||||||
|
_eventAggregator.GetEvent<AlarmEvent>().Publish(
|
||||||
|
(scope, entry.Fingerprint, $"通道 {entry.MethodName} 连续失败 {count} 次,已暂停"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, token);
|
}, token);
|
||||||
}
|
}
|
||||||
@@ -209,6 +249,8 @@ namespace UIShare.GlobalVariable
|
|||||||
_cts?.Dispose();
|
_cts?.Dispose();
|
||||||
_cts = null;
|
_cts = null;
|
||||||
_registeredMethods.Clear();
|
_registeredMethods.Clear();
|
||||||
|
_failureCounts.Clear();
|
||||||
|
_suspendedChannels.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user