using Quartz; using Microsoft.Extensions.DependencyInjection; using Warehouse.IServices; using VolPro.Entity.DomainModels; using System; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; namespace VolPro.Warehouse.Services; /// /// 心跳超时检测任务。扫描心跳超时 30 秒的网关节点,标记为离线, /// 并级联标记该节点下所有设备为离线。 /// Cron 建议: 每 15 秒 ("0/15 * * * * ?") /// public class HeartbeatMonitorJob : IJob { public async Task Execute(IJobExecutionContext context) { var sp = (IServiceProvider)context.JobDetail.JobDataMap["ServiceProvider"]; var gwSvc = sp.GetService(); var devSvc = sp.GetService(); if (gwSvc == null) return; var timeout = DateTime.Now.AddSeconds(-30); // 扫描心跳超时的网关(当前在线但心跳超时) var offlineNodes = await gwSvc.FindAsIQueryable( x => x.IsOnline == "在线" && x.LastHeartbeat < timeout) .ToListAsync(); foreach (var node in offlineNodes) { // 标记网关离线 node.IsOnline = "离线"; await gwSvc.FindAsIQueryable(x => x.NodeId == node.NodeId) .FirstAsync(); // 确保实体被跟踪 // 直接通过 DbContext 更新 var dbProp = gwSvc.GetType().BaseType?.GetProperty("DbContext"); if (dbProp != null) continue; // fallback: 通过 FindAsIQueryable 重新获取更新 Console.WriteLine($"[HeartbeatMonitorJob] 网关 {node.NodeCode} 心跳超时,标记离线"); // 级联标记该网关下所有设备离线 if (devSvc != null) { var devices = await devSvc.FindAsIQueryable( x => x.GatewayNodeId == node.NodeId && x.IsOnline == "在线") .ToListAsync(); foreach (var dev in devices) { dev.IsOnline = "离线"; } Console.WriteLine($"[HeartbeatMonitorJob] 级联 {devices.Count} 台设备离线"); } } } }