fix: HardwareDataBroadcaster幂等Discover与静默异常增强(失败计数+通道暂停+日志)
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
using Common.Attributes;
|
||||
using DeviceCommand.Base;
|
||||
using Logger;
|
||||
using Model.Models;
|
||||
using Prism.Events;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
@@ -41,6 +43,18 @@ namespace UIShare.GlobalVariable
|
||||
private CancellationTokenSource? _cts;
|
||||
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>
|
||||
public TimeSpan SampleInterval
|
||||
{
|
||||
@@ -89,9 +103,12 @@ namespace UIShare.GlobalVariable
|
||||
/// <summary>
|
||||
/// 扫描 GlobalInfo.HardwarePool 中所有已创建的物理设备,
|
||||
/// 反查可监测方法并编译为委托。每个指纹只注册一次,反射只执行一次。
|
||||
/// <para>幂等:首次调用后再次调用不会 Clear 重扫,避免多作用域重复 Discover 导致短暂采样中断。</para>
|
||||
/// </summary>
|
||||
public void Discover()
|
||||
{
|
||||
if (_discovered) return;
|
||||
_discovered = true;
|
||||
_registeredMethods.Clear();
|
||||
|
||||
foreach (var poolEntry in _globalInfo.HardwarePool)
|
||||
@@ -157,6 +174,11 @@ namespace UIShare.GlobalVariable
|
||||
|
||||
foreach (var entry in _registeredMethods)
|
||||
{
|
||||
string channelKey = entry.Fingerprint + "|" + entry.MethodName;
|
||||
|
||||
// 已暂停的通道跳过采样
|
||||
if (_suspendedChannels.ContainsKey(channelKey)) continue;
|
||||
|
||||
// fire-and-forget:每个通道独立采样,完成后自行广播
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
@@ -167,6 +189,9 @@ namespace UIShare.GlobalVariable
|
||||
|
||||
if (!double.TryParse(raw, out double value)) return;
|
||||
|
||||
// 采样成功,重置失败计数
|
||||
_failureCounts.TryRemove(channelKey, out _);
|
||||
|
||||
// 向所有引用该物理设备的作用域分别广播
|
||||
var scopes = GetScopesForFingerprint(entry.Fingerprint);
|
||||
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);
|
||||
}
|
||||
@@ -209,6 +249,8 @@ namespace UIShare.GlobalVariable
|
||||
_cts?.Dispose();
|
||||
_cts = null;
|
||||
_registeredMethods.Clear();
|
||||
_failureCounts.Clear();
|
||||
_suspendedChannels.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user