101 lines
3.3 KiB
C#
101 lines
3.3 KiB
C#
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 {
|
|
/// <summary>
|
|
/// 心跳管理器实现
|
|
/// </summary>
|
|
public class HeartbeatManager : IHeartbeatManager, IDisposable {
|
|
private readonly ConcurrentDictionary<string, ProcessHeartbeat> _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<string> ProcessTimeout;
|
|
|
|
public HeartbeatManager() {
|
|
_heartbeats = new ConcurrentDictionary<string, ProcessHeartbeat>();
|
|
_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<string>();
|
|
|
|
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();
|
|
}
|
|
}
|
|
}
|