定时任务调度
一、核心功能
定时任务调度是 Furion.Pure 框架提供的轻量级作业调度系统,支持多种触发方式和分布式部署。
1.1 核心价值
- 多种触发方式:支持 Cron 表达式、周期触发、一次性触发等
- 分布式支持:支持集群部署,避免任务重复执行
- 可视化管理:提供 Web Dashboard 管理界面
- 持久化存储:支持任务执行记录持久化
- 灵活配置:支持属性配置和代码配置
二、触发方式
2.1 Cron 表达式触发
使用 [Cron] 特性配置 Cron 表达式:
csharp
[Cron("0 0 2 * * ?")]
public class DailyReportJob : IJob
{
public async Task ExecuteAsync(JobExecutingContext context)
{
// 每天凌晨 2 点执行
}
}
2.2 周期触发
使用 [Period] 特性配置固定周期:
csharp
[Period(Seconds = 60)]
public class HeartbeatJob : IJob
{
public async Task ExecuteAsync(JobExecutingContext context)
{
// 每 60 秒执行一次
}
}
2.3 快捷周期特性
框架提供了多种快捷周期特性:
| 特性 | 说明 |
|---|---|
[Secondly] |
每秒执行 |
[Minutely] |
每分钟执行 |
[Hourly] |
每小时执行 |
[Daily] |
每天执行 |
[Weekly] |
每周执行 |
[Monthly] |
每月执行 |
[Yearly] |
每年执行 |
2.4 指定时间触发
使用 [DailyAt]、[HourlyAt] 等特性指定具体时间:
csharp
[DailyAt("08:00", "18:00")]
public class WorkTimeJob : IJob
{
public async Task ExecuteAsync(JobExecutingContext context)
{
// 每天 8 点和 18 点执行
}
}
三、实现流程
3.1 服务注册
在 Startup.cs 中调用:
csharp
services.AddSchedule();
注册逻辑:
| 步骤 | 操作 | 说明 |
|---|---|---|
| 1 | 构建调度器配置 | 创建 ScheduleOptionsBuilder |
| 2 | 注册日志服务 | 添加 IScheduleLogger |
| 3 | 注册调度器工厂 | 添加 ISchedulerFactory |
| 4 | 注册取消 Token | 添加 IJobCancellationToken |
| 5 | 注册后台服务 | 添加 ScheduleHostedService |
3.2 作业执行流程
┌─────────────────────────────────────────────────────────────┐
│ 调度器启动阶段 │
├─────────────────────────────────────────────────────────────┤
│ 1. ScheduleHostedService 启动 │
│ └── 创建调度器实例 │
├─────────────────────────────────────────────────────────────┤
│ 2. 扫描所有实现 IJob 的类 │
│ └── 注册到调度器 │
├─────────────────────────────────────────────────────────────┤
│ 3. 根据触发配置计算下次执行时间 │
│ └── 注册到触发器队列 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 作业执行阶段 │
├─────────────────────────────────────────────────────────────┤
│ 1. 触发器触发 │
│ └── 创建作业执行上下文 │
├─────────────────────────────────────────────────────────────┤
│ 2. 调用作业执行器 │
│ └── 执行 IJob.ExecuteAsync() │
├─────────────────────────────────────────────────────────────┤
│ 3. 记录执行结果 │
│ └── 更新持久化存储 │
└─────────────────────────────────────────────────────────────┘
四、作业上下文
JobExecutingContext 提供了丰富的上下文信息:
csharp
public class JobExecutingContext
{
/// <summary>
/// 作业 ID
/// </summary>
public string JobId { get; }
/// <summary>
/// 作业名称
/// </summary>
public string JobName { get; }
/// <summary>
/// 触发类型
/// </summary>
public TriggerType TriggerType { get; }
/// <summary>
/// 执行次数
/// </summary>
public int ExecuteCount { get; }
/// <summary>
/// 取消 Token
/// </summary>
public CancellationToken CancellationToken { get; }
/// <summary>
/// 作业参数
/// </summary>
public object[] Arguments { get; }
}
五、配置选项
ScheduleOptionsBuilder 提供了丰富的配置项:
| 配置项 | 默认值 | 说明 |
|---|---|---|
ClusterId |
null |
集群 ID,用于分布式部署 |
LogEnabled |
true |
是否启用日志 |
UnobservedTaskExceptionHandler |
null |
未处理异常处理器 |
5.1 配置示例
csharp
services.AddSchedule(options =>
{
options.ClusterId = "cluster-001";
options.LogEnabled = true;
options.UnobservedTaskExceptionHandler = (sender, args) =>
{
// 处理未观察到的异常
};
});
六、高级特性
6.1 分布式部署
配置 ClusterId 实现分布式部署:
csharp
services.AddSchedule(options =>
{
options.ClusterId = "production-cluster";
});
框架会自动协调集群中的任务执行,确保同一任务只在一个节点上执行。
6.2 作业参数
通过特性传递参数:
csharp
[JobDetail(Arguments = new object[] { "param1", 123 })]
[Cron("0 0 * * * ?")]
public class ParameterizedJob : IJob
{
public async Task ExecuteAsync(JobExecutingContext context)
{
var param1 = context.Arguments[0] as string;
var param2 = (int)context.Arguments[1];
}
}
6.3 作业监控
实现 IJobMonitor 接口监控作业执行:
csharp
public class JobMonitor : IJobMonitor
{
public void OnExecuting(JobExecutingContext context)
{
// 作业开始执行
}
public void OnExecuted(JobExecutedContext context)
{
// 作业执行完成
}
}
6.4 持久化存储
实现 IJobPersistence 接口自定义持久化存储:
csharp
public class CustomJobPersistence : IJobPersistence
{
public Task SaveExecutionRecordAsync(JobExecutionRecord record)
{
// 保存执行记录
}
public Task<List<JobExecutionRecord>> GetExecutionRecordsAsync(string jobId)
{
// 获取执行记录
}
}
6.5 动态作业
支持动态创建和注册作业:
csharp
public class JobController
{
private readonly ISchedulerFactory _schedulerFactory;
public JobController(ISchedulerFactory schedulerFactory)
{
_schedulerFactory = schedulerFactory;
}
public void AddJob()
{
var scheduler = _schedulerFactory.Create();
scheduler.Schedule<MyDynamicJob>()
.Cron("0 0 1 * * ?")
.Build();
}
}
七、Dashboard
框架提供了 Web Dashboard 用于可视化管理作业:
7.1 启用 Dashboard
csharp
services.AddSchedule(options =>
{
options.UseDashboard();
});
7.2 访问地址
默认访问地址:http://localhost:5000/schedule
7.3 Dashboard 功能
| 功能 | 说明 |
|---|---|
| 作业列表 | 查看所有已注册的作业 |
| 执行记录 | 查看作业执行历史 |
| 手动触发 | 手动触发作业执行 |
| 暂停/恢复 | 暂停或恢复作业 |
八、核心文件
| 文件 | 说明 |
|---|---|
ScheduleServiceCollectionExtensions.cs |
调度服务扩展方法 |
IJob.cs |
作业接口 |
IScheduler.cs |
调度器接口 |
ISchedulerFactory.cs |
调度器工厂接口 |
Trigger.cs |
触发器基类 |
CronTrigger.cs |
Cron 表达式触发器 |
PeriodTrigger.cs |
周期触发器 |
JobExecutingContext.cs |
作业执行上下文 |
ScheduleHostedService.cs |
调度后台服务 |
ScheduleLogger.cs |
调度日志服务 |
九、总结
定时任务调度通过灵活的触发配置和强大的扩展能力,实现了轻量级的作业调度系统。核心设计思想:
- 声明式配置:通过特性声明作业触发规则,无需手动注册
- 多触发方式:支持 Cron 表达式、周期触发、指定时间触发等多种方式
- 分布式支持:内置集群协调机制,支持分布式部署
- 可视化管理:提供 Web Dashboard 便于监控和管理
- 高度可扩展:支持自定义持久化、监控和触发器
这种设计使得开发者可以轻松实现定时任务,无需引入复杂的第三方调度框架。