175 lines
6.1 KiB
Markdown
175 lines
6.1 KiB
Markdown
# 定时任务 API 化整改方案 v1.0
|
||
|
||
> **版本**: 1.0
|
||
> **日期**: 2026-06-04
|
||
> **背景**: VolPro 框架的 Quartz 机制基于 `[ApiTask]` + URL 调用,不支持 `IJob` 接口
|
||
> **现状**: 4 个 IJob 实现(SyncDevices/HeartbeatMonitor/RealtimePoll/RuleEngineJob)需迁移为 API 端点
|
||
|
||
---
|
||
|
||
## 1. 影响范围
|
||
|
||
| 任务 | 当前文件 | 需改为 | 调度间隔 |
|
||
|------|------|------|:---:|
|
||
| 设备同步 | `SyncDevicesJob.cs` (IJob) | Controller + `[ApiTask]` | 每5分钟 |
|
||
| 心跳监控 | `HeartbeatMonitorJob.cs` (IJob) | Controller + `[ApiTask]` | 每15秒 |
|
||
| 实时轮询 | `RealtimePollJob.cs` (IJob) | Controller + `[ApiTask]` | 每10秒 |
|
||
| 规则引擎 | `RuleEngineJob.cs` (IJob) | Controller + `[ApiTask]` | 每10秒 |
|
||
|
||
---
|
||
|
||
## 2. 整改步骤
|
||
|
||
### 步骤 T1: 创建任务调度 Controller(预计 30min)
|
||
|
||
**新建文件**: `api_sqlsugar/VolPro.WebApi/Controllers/Warehouse/TaskController.cs`
|
||
|
||
```csharp
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.Extensions.DependencyInjection;
|
||
using VolPro.Core.Filters;
|
||
using Warehouse.Services;
|
||
|
||
namespace Warehouse.Controllers;
|
||
|
||
/// <summary>
|
||
/// 定时任务 API 端点。
|
||
/// VolPro 框架通过 Sys_QuartzOptions 配置 URL+Cron 定时调用。
|
||
/// 每个方法加 [ApiTask] 属性以允许框架匿名调用。
|
||
/// </summary>
|
||
[ApiController]
|
||
[Route("api/task")]
|
||
public class TaskController : Controller
|
||
{
|
||
/// <summary>T1: 设备同步 — 遍历在线网关触发全量设备同步</summary>
|
||
[ApiTask]
|
||
[HttpGet, HttpPost, Route("syncDevices")]
|
||
public async Task<IActionResult> SyncDevices()
|
||
{
|
||
var sp = HttpContext.RequestServices;
|
||
var engine = sp.GetService<SyncDevicesJob>();
|
||
if (engine != null) await engine.Execute(null!);
|
||
return Ok(new { time = DateTime.Now, status = "ok" });
|
||
}
|
||
|
||
/// <summary>T2: 心跳监控 — 扫描超时网关标记离线</summary>
|
||
[ApiTask]
|
||
[HttpGet, HttpPost, Route("heartbeatMonitor")]
|
||
public async Task<IActionResult> HeartbeatMonitor()
|
||
{
|
||
var sp = HttpContext.RequestServices;
|
||
var engine = sp.GetService<HeartbeatMonitorJob>();
|
||
if (engine != null) await engine.Execute(null!);
|
||
return Ok(new { time = DateTime.Now, status = "ok" });
|
||
}
|
||
|
||
/// <summary>T3: 实时轮询 — 拉取 MC4 IoT 实时值</summary>
|
||
[ApiTask]
|
||
[HttpGet, HttpPost, Route("realtimePoll")]
|
||
public async Task<IActionResult> RealtimePoll()
|
||
{
|
||
var sp = HttpContext.RequestServices;
|
||
var engine = sp.GetService<RealtimePollJob>();
|
||
if (engine != null) await engine.Execute(null!);
|
||
return Ok(new { time = DateTime.Now, status = "ok" });
|
||
}
|
||
|
||
/// <summary>T4: 规则引擎 — 评估规则+执行动作</summary>
|
||
[ApiTask]
|
||
[HttpGet, HttpPost, Route("ruleEngine")]
|
||
public async Task<IActionResult> RuleEngine()
|
||
{
|
||
var sp = HttpContext.RequestServices;
|
||
var engine = sp.GetService<RuleEngineService>();
|
||
if (engine != null) await engine.EvaluateAllAsync();
|
||
return Ok(new { time = DateTime.Now, status = "ok" });
|
||
}
|
||
}
|
||
```
|
||
|
||
### 步骤 T2: 注册 DI(预计 10min)
|
||
|
||
**编辑文件**: `api_sqlsugar/VolPro.Core/Extensions/AutofacManager/AutofacContainerModuleExtension.cs`
|
||
|
||
或在 Warehouse 项目的 Startup/Module 中注册:
|
||
|
||
```csharp
|
||
// 在 Autofac 注册块中添加
|
||
builder.RegisterType<SyncDevicesJob>().AsSelf().InstancePerLifetimeScope();
|
||
builder.RegisterType<HeartbeatMonitorJob>().AsSelf().InstancePerLifetimeScope();
|
||
builder.RegisterType<RealtimePollJob>().AsSelf().InstancePerLifetimeScope();
|
||
builder.RegisterType<RuleEngineService>().AsSelf().InstancePerLifetimeScope();
|
||
```
|
||
|
||
如果已由 VolPro 框架自动扫描 Services 目录,则跳过此步骤。
|
||
|
||
### 步骤 T3: 管理端配置任务(预计 15min)
|
||
|
||
在 Vol.Pro 管理端 → Quartz 管理 → 新建 4 个任务:
|
||
|
||
| TaskName | ApiUrl | Cron | Method |
|
||
|------|------|------|:--:|
|
||
| 设备同步 | `/api/task/syncDevices` | `0 */5 * * * ?` | POST |
|
||
| 心跳监控 | `/api/task/heartbeatMonitor` | `0/15 * * * * ?` | POST |
|
||
| 实时轮询 | `/api/task/realtimePoll` | `0/10 * * * * ?` | POST |
|
||
| 规则引擎 | `/api/task/ruleEngine` | `0/10 * * * * ?` | POST |
|
||
|
||
### 步骤 T4: 保留或删除 IJob 文件(预计 5min)
|
||
|
||
**保留** IJob 实现类(`SyncDevicesJob.cs` 等)不删除——Controller 通过 DI 获取它们并调用 `Execute()`。
|
||
|
||
只需将 IJob 实现类用 `IServiceProvider` 获取(而非 Quartz 的 `JobDataMap`),因为 Controller 不传 `IJobExecutionContext`。修改 `Execute` 方法签名:
|
||
|
||
```csharp
|
||
// 旧: 依赖 IJobExecutionContext.JobDataMap
|
||
public async Task Execute(IJobExecutionContext context)
|
||
{
|
||
var sp = (IServiceProvider)context.JobDetail.JobDataMap["ServiceProvider"];
|
||
...
|
||
}
|
||
|
||
// 新: 注入 IServiceProvider 为构造函数参数
|
||
public class HeartbeatMonitorJob : IJob
|
||
{
|
||
private readonly IServiceProvider _sp;
|
||
public HeartbeatMonitorJob(IServiceProvider sp) { _sp = sp; }
|
||
|
||
public async Task Execute(IJobExecutionContext? context)
|
||
{
|
||
var gwSvc = _sp.GetService<Igateway_nodesService>();
|
||
var devRepo = _sp.GetService<Ibase_deviceRepository>();
|
||
...
|
||
}
|
||
}
|
||
```
|
||
|
||
### 步骤 T5: 编译验证(预计 10min)
|
||
|
||
- [ ] `dotnet build api_sqlsugar/VolPro.WebApi` → 0 错误
|
||
- [ ] 确认 `[ApiTask]` 不与其他权限 Filter 冲突
|
||
|
||
---
|
||
|
||
## 3. 改动文件汇总
|
||
|
||
| 步骤 | 文件 | 改动 |
|
||
|:---:|------|------|
|
||
| T1 | `VolPro.WebApi/Controllers/Warehouse/TaskController.cs` | 新建,4 个 `[ApiTask]` 端点 |
|
||
| T2 | DI 注册 | 可能不需改动(VolPro 自动扫描) |
|
||
| T3 | 管理端 Sys_QuartzOptions | 新建 4 条任务记录 |
|
||
| T4 | 4 个 IJob 实现 | 构造函数改用 IServiceProvider 注入 |
|
||
| T5 | 全量编译 | 0 错误 |
|
||
|
||
---
|
||
|
||
## 4. 原 IJob 文件处理方案
|
||
|
||
| 文件 | 处理 |
|
||
|------|------|
|
||
| `SyncDevicesJob.cs` | 构造函数注入 IServiceProvider,Execute 参数改为 nullable |
|
||
| `HeartbeatMonitorJob.cs` | 同上 |
|
||
| `RealtimePollJob.cs` | 同上 |
|
||
| `RuleEngineJob.cs` | 删除(RuleEngineService 本身就是普通类,不继承 IJob) |
|
||
|
||
> `RuleEngineJob.cs` 可直接删除——`RuleEngineService` 是普通类,已被 TaskController 直接调用。
|