using System; using System.Threading; using System.Threading.Tasks; using Serilog; namespace Protocol376Simulator.Services { /// /// 心跳服务类,负责处理定时发送心跳 /// public class HeartbeatService { private readonly string _deviceIdentifier; private readonly Func _heartbeatAction; private CancellationTokenSource _heartbeatCancellationTokenSource; private Task _heartbeatTask; private readonly object _heartbeatLock = new object(); private bool _isRunning = false; private TimeSpan _heartbeatInterval = TimeSpan.FromMinutes(4); // 默认心跳间隔4分钟 private int _successfulHeartbeats = 0; private DateTime _lastHeartbeatTime = DateTime.MinValue; /// /// 当心跳发送成功时触发 /// public event EventHandler HeartbeatSent; /// /// 成功的心跳次数 /// public int SuccessfulHeartbeats => _successfulHeartbeats; /// /// 最后一次心跳时间 /// public DateTime LastHeartbeatTime => _lastHeartbeatTime; /// /// 心跳间隔 /// public TimeSpan HeartbeatInterval { get => _heartbeatInterval; set => _heartbeatInterval = value; } /// /// 心跳是否正在运行 /// public bool IsRunning => _isRunning; /// /// 构造函数 /// /// 设备标识(用于日志) /// 执行心跳的委托函数 public HeartbeatService(string deviceIdentifier, Func heartbeatAction) { _deviceIdentifier = deviceIdentifier; _heartbeatAction = heartbeatAction ?? throw new ArgumentNullException(nameof(heartbeatAction)); } /// /// 启动心跳服务 /// public void Start() { lock (_heartbeatLock) { if (_isRunning) { return; } _heartbeatCancellationTokenSource?.Cancel(); _heartbeatCancellationTokenSource = new CancellationTokenSource(); _heartbeatTask = RunHeartbeatAsync(_heartbeatCancellationTokenSource.Token); _isRunning = true; Log.Information("{DeviceId} 已启动心跳服务,间隔: {Interval}分钟", _deviceIdentifier, _heartbeatInterval.TotalMinutes); } } /// /// 停止心跳服务 /// public void Stop() { lock (_heartbeatLock) { if (!_isRunning) { return; } _heartbeatCancellationTokenSource?.Cancel(); _isRunning = false; Log.Information("{DeviceId} 已停止心跳服务", _deviceIdentifier); } } /// /// 重置心跳计数 /// public void ResetHeartbeatCount() { _successfulHeartbeats = 0; } /// /// 记录心跳成功 /// public void RecordHeartbeatSuccess() { _successfulHeartbeats++; _lastHeartbeatTime = DateTime.Now; HeartbeatSent?.Invoke(this, _lastHeartbeatTime); } /// /// 设置心跳间隔 /// /// 间隔分钟数 public void SetHeartbeatInterval(double minutes) { if (minutes <= 0) { throw new ArgumentException("心跳间隔必须大于0分钟", nameof(minutes)); } _heartbeatInterval = TimeSpan.FromMinutes(minutes); Log.Information("{DeviceId} 心跳间隔已设置为 {Interval}分钟", _deviceIdentifier, minutes); // 如果心跳正在运行,重启心跳任务以应用新的间隔 if (_isRunning) { Stop(); Start(); } } /// /// 运行心跳任务 /// private async Task RunHeartbeatAsync(CancellationToken cancellationToken) { try { // 初始等待一段随机时间,避免多个设备同时发送心跳 int initialDelayMs = new Random().Next(1000, 5000); await Task.Delay(initialDelayMs, cancellationToken); while (!cancellationToken.IsCancellationRequested) { try { // 执行心跳操作 await _heartbeatAction(); // 记录心跳成功 RecordHeartbeatSuccess(); Log.Debug("{DeviceId} 心跳已发送,下一次将在 {NextTime} 发送", _deviceIdentifier, DateTime.Now.Add(_heartbeatInterval).ToString("HH:mm:ss")); } catch (Exception ex) { Log.Error(ex, "{DeviceId} 发送心跳时发生错误: {ErrorMessage}", _deviceIdentifier, ex.Message); } // 等待下一次心跳 await Task.Delay(_heartbeatInterval, cancellationToken); } } catch (OperationCanceledException) { // 任务被取消,正常退出 Log.Debug("{DeviceId} 心跳任务已取消", _deviceIdentifier); } catch (Exception ex) { Log.Error(ex, "{DeviceId} 心跳任务发生异常: {ErrorMessage}", _deviceIdentifier, ex.Message); } finally { lock (_heartbeatLock) { _isRunning = false; } } } /// /// 立即发送一次心跳 /// public async Task SendHeartbeatImmediatelyAsync() { try { await _heartbeatAction(); RecordHeartbeatSuccess(); Log.Information("{DeviceId} 已立即发送心跳", _deviceIdentifier); } catch (Exception ex) { Log.Error(ex, "{DeviceId} 立即发送心跳时发生错误: {ErrorMessage}", _deviceIdentifier, ex.Message); throw; } } } }