using System.Net.WebSockets; namespace YD_YiLu.Api.WebSockets { public class DeviceHeartbeatCleanupService : BackgroundService { private readonly ICameraDeviceSocketRegistry _registry; private readonly ILogger _logger; public DeviceHeartbeatCleanupService( ICameraDeviceSocketRegistry registry, ILogger logger) { _registry = registry; _logger = logger; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { var interval = TimeSpan.FromSeconds(30); // 每30秒检查 var timeout = TimeSpan.FromSeconds(90); // 超过90秒算离线 while (!stoppingToken.IsCancellationRequested) { try { var timeoutDevices = _registry.GetTimeoutDevices(timeout); foreach (var sn in timeoutDevices) { if (_registry.TryGet(sn, out var socket)) { try { if (socket.State == WebSocketState.Open) { await socket.CloseAsync( WebSocketCloseStatus.NormalClosure, "Heartbeat timeout", stoppingToken); } } catch { } _registry.Unregister(sn); _logger.LogWarning("⚠️ 设备超时已移除: {0}", sn); } } } catch (Exception ex) { _logger.LogError(ex, "心跳清理异常"); } await Task.Delay(interval, stoppingToken); } } } }