using IpcLibrary.Core; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IpcLibrary.Services { /// /// 心跳管理器实现 /// public class HeartbeatManager : IHeartbeatManager, IDisposable { private readonly ConcurrentDictionary _heartbeats; private readonly Timer _monitorTimer; private readonly object _lock = new object(); private TimeSpan _heartbeatInterval = TimeSpan.FromSeconds(5); private TimeSpan _timeoutThreshold = TimeSpan.FromSeconds(15); private bool _disposed; public event EventHandler ProcessTimeout; public HeartbeatManager() { _heartbeats = new ConcurrentDictionary(); _monitorTimer = new Timer(MonitorHeartbeats, null, _heartbeatInterval, _heartbeatInterval); } public void StartMonitoring(string processId) { if (string.IsNullOrEmpty(processId)) throw new ArgumentException("进程ID不能为空", nameof(processId)); var heartbeat = new ProcessHeartbeat { ProcessId = processId, LastHeartbeat = DateTime.UtcNow, IsActive = true }; _heartbeats.AddOrUpdate(processId, heartbeat, (key, old) => heartbeat); } public void StopMonitoring(string processId) { if (_heartbeats.TryGetValue(processId, out var heartbeat)) { heartbeat.IsActive = false; _heartbeats.TryRemove(processId, out _); } } public void UpdateHeartbeat(string processId) { if (_heartbeats.TryGetValue(processId, out var heartbeat)) { heartbeat.LastHeartbeat = DateTime.UtcNow; } } public void SetHeartbeatInterval(TimeSpan interval) { if (interval <= TimeSpan.Zero) throw new ArgumentException("心跳间隔必须大于零", nameof(interval)); lock (_lock) { _heartbeatInterval = interval; _monitorTimer?.Change(interval, interval); } } public void SetTimeoutThreshold(TimeSpan timeout) { if (timeout <= TimeSpan.Zero) throw new ArgumentException("超时阈值必须大于零", nameof(timeout)); _timeoutThreshold = timeout; } private void MonitorHeartbeats(object state) { if (_disposed) return; var now = DateTime.UtcNow; var timedOutProcesses = new List(); foreach (var kvp in _heartbeats) { var heartbeat = kvp.Value; if (heartbeat.IsActive && now - heartbeat.LastHeartbeat > _timeoutThreshold) { timedOutProcesses.Add(kvp.Key); heartbeat.IsActive = false; } } foreach (var processId in timedOutProcesses) { ProcessTimeout?.Invoke(this, processId); } } public void Dispose() { if (_disposed) return; _disposed = true; _monitorTimer?.Dispose(); _heartbeats.Clear(); } } }