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();
}
}
}