Files
SecMPS/api_sqlsugar/Warehouse/Services/HeartbeatMonitorJob.cs

75 lines
2.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Quartz;
using Microsoft.Extensions.DependencyInjection;
using Warehouse.IServices;
using VolPro.Entity.DomainModels;
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Warehouse.IRepositories;
namespace VolPro.Warehouse.Services;
/// <summary>
/// 心跳超时检测任务。扫描心跳超时 30 秒的网关节点,标记为离线,
/// 并级联标记该节点下所有设备为离线。
/// Cron 建议: 每 15 秒 ("0/15 * * * * ?")
///
/// 设备与网关的关联通过 AdapterCode 前缀匹配(如设备 AdapterCode="MC4:31ku" 匹配网关 AdapterTypes="MC4:31ku")。
/// </summary>
public class HeartbeatMonitorJob : IJob
{
public async Task Execute(IJobExecutionContext context)
{
var sp = (IServiceProvider)context.JobDetail.JobDataMap["ServiceProvider"];
if (sp == null) return;
var gwSvc = sp.GetService<Igateway_nodesService>();
var gwRepo = sp.GetService<Igateway_nodesRepository>();
var devRepo = sp.GetService<Ibase_deviceRepository>();
if (gwSvc == null || gwRepo == null || devRepo == 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 = "离线";
try { gwRepo.Update(node); } catch { }
Console.WriteLine($"[HeartbeatMonitorJob] 网关 {node.NodeCode} 心跳超时,标记离线");
// 级联标记该网关下所有设备离线(批量 SQL
try
{
var adapterPrefixes = (node.AdapterTypes ?? "")
.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(t => t.Trim()).ToList();
if (adapterPrefixes.Any())
{
var allDevices = await devRepo.FindAsIQueryable(
d => d.IsOnline == "在线").ToListAsync();
var matched = allDevices
.Where(d => adapterPrefixes.Any(p => (d.AdapterCode ?? "").StartsWith(p)))
.ToList();
if (matched.Any())
{
foreach (var dev in matched) dev.IsOnline = "离线";
devRepo.UpdateRange(matched);
Console.WriteLine($"[HeartbeatMonitorJob] 级联 {matched.Count} 台设备离线");
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine($"[HeartbeatMonitorJob] 级联离线失败: {ex.Message}");
}
}
}
}