定时任务
builder.Services.AddLedonScheduling();
public class CleanupTask : IScheduledTask
{
public string CronExpression => "0 3 * * *"; // 每天 3 点(UTC)
public async Task ExecuteAsync(CancellationToken ct = default)
{
await db.CleanupAsync(ct);
}
}
实现 IScheduledTask 即被自动发现,宿主启动后按各自 cron 驱动执行。
规则
- cron 表达式:支持 5 段(标准)与 6 段(含秒,如
*/1 * * * * *)——按字段数自动判别; - 时区:默认 UTC,
o.TimeZone可改(cron 按此时区解释,夏令自动处理); - 独立执行:每个任务独立循环 + 独立 DI 作用域 + 独立 span,单任务失败只记日志,不影响其它任务与调度;
- 启动即失败:cron 写错(解析不过)在启动时抛异常——不拖到运行时静默不执行。
执行语义
同一任务的执行天然串行——循环等待上一次执行结束后才走向下一个触发点,不会并发重跑。
执行耗时跨过后续触发点时的行为(misfire 策略)由 CatchUpMissedTriggers 控制:
| 设置 | 行为 |
|---|---|
false(默认) |
执行期间错过的触发点被丢弃;下一次执行为"执行完毕后"的下一个未来触发点 |
true |
执行完毕后立即补跑错过的触发(逐个、仍串行),追平后恢复正常节奏 |
builder.Services.AddLedonScheduling(o => o.CatchUpMissedTriggers = true);
执行时间短于触发间隔时两种设置无差异。补跑适合"绝不能错过"的周期语义,但注意补跑期间新触发会继续积压、执行时间叠加——任务长期超时本身就是需要告警的问题。
多实例部署:领导权选举
默认每个实例独立执行全部定时任务(单实例语义)。多实例部署下避免重复执行,开启领导权选举:
builder.Services.AddLedonScheduling(o =>
{
o.LeaderElection = SchedulerLeaderElection.Redis; // 仅领导实例执行
o.RedisConnectionString = "localhost:6379";
});
- 基于 Redis 锁(SET NX PX):抢到锁的实例成为领导,TTL 默认 30s、每 1/3 周期续约;
- 掉锁自动让出:续约失败(网络分区/Redis 故障)时本实例停止任务循环,回到竞选;
- 领导权转移期间触发点不补跑(与默认 misfire 策略一致);
- 自建锁(etcd、数据库、K8s Lease 等)可实现
ISchedulerLock注册替换; - 未配置时零开销(不注册锁即单实例语义)。
长周期语义
到点判断基于 Task.Delay 到下一个发生时刻,宿主机休眠/挂起错过的时间点不会补偿触发(无 misfire 回补)。对"绝不能错过"的周期语义,用外部调度器(系统 cron / K8s CronJob)触发 HTTP 端点更稳妥。
执行历史与手动触发
// 历史:进程内有界环形缓冲(默认 100 条),运维排障/重放确认用
var history = provider.GetRequiredService<IScheduledTaskExecutionHistory>();
var last = history.Latest(nameof(ReconcileTask)); // TaskName/StartedAt/Duration/Success/Error/Manual
// 手动触发:等不到下一个 cron 触发点时立即执行一次
var invoker = provider.GetRequiredService<ISchedulerInvoker>();
await invoker.InvokeAsync<ReconcileTask>(ct); // 或按名称(大小写不敏感)
await invoker.InvokeAsync("ReconcileTask", ct); // 未注册的名称返回 false
- 手动触发与 cron 触发走同一套执行、历史与指标(
Manual = true标记); - 多实例部署时各实例只记自己的执行——全局视图接可观测性后端的 span/指标;
- 典型用法:把触发暴露成受权限保护的运维端点("立刻重跑失败的对账任务")。
指标
Ledon.Scheduling Meter(AddLedonObservability() 自动收集):
| 指标 | 含义 |
|---|---|
ledon.scheduler.task.executions |
执行次数(tag:task、status) |
ledon.scheduler.task.missed_triggers |
执行耗时跨过触发点、被丢弃的触发数 |
ledon.scheduler.task.manual_invocations |
经 ISchedulerInvoker 的手动触发次数 |
ledon.scheduler.leadership.lost |
多实例部署下领导权让出次数 |
默认(丢弃)模式下,执行耗时跨过下一个触发点会记一次 missed_triggers 并打 Warning——这是任务长期超时的告警信号。