Skip to content
bitzorcas
中EN

Reference

数据库驱动后台作业与调度安全:Quartz 实操指南

告别难以运维的外部 Cron!深入解析 BitzOrcas.Modern 数据库驱动后台作业体系,揭秘类型化 IJobExecutor 调度器无关设计、Quartz 持久化集群防并发堆积与 Operations 探针。

Last updated

在分布式企业级系统中,很多团队在做后台任务时经常踩进几个大坑:

  • 依赖外部系统 Crontab:在服务器 Linux crontab 里写一堆 curl http://localhost/api/cron/sync,一旦服务器漂移或扩容,任务全部失控;
  • 内存定时器(Timer)并发击穿:单机 System.Threading.Timer 遇到大任务执行慢时,前一个任务还没跑完,后一个又被触发,导致数据库连接池被直接打满撑爆;
  • 多实例重复执行:服务部署了 3 个副本,零点一到,3 台服务器同时执行“自动扣费”,导致客户被扣了 3 次钱!

BitzOrcas.Modern 采用数据库驱动的 Quartz 集群 + 调度器中立的 IJobExecutor<T> 架构:业务只写纯粹的用例执行器,底层由持久化集群保证全局唯一触发与故障自动转移(Failover)。

后台作业调度与执行全景

单实例抢占触发

1. BackgroundJobCatalog (启动加载配置声明)

2. Quartz 持久化集群调度器

3. IJobExecutorDispatcher (定位类型化绑定)

4. IJobExecutor (执行业务纯用例)

5. 数据库持久化变更

6. QuartzJobExecutionAuditor (记录耗时与结果)


第一步:声明类型化任务身份与调度器中立执行器

BitzOrcas 的第一原则是:业务用例绝对不依赖 Quartz 具体的 IJob 或 JobExecutionContext。

在模块中,我们定义一个强类型的任务身份与对应的 IJobExecutor<T>:

AuditRetentionJobExecutor.cs: 类型化执行器
using BitzOrcas.Application.Abstractions.Jobs;
using BitzOrcas.Domain.Results;
namespace BitzOrcas.Auditing.Application.Jobs;
// 1. 声明稳定全局唯一的 Job 身份
public static class AuditJobIdentities
{
public sealed class RetentionPrune : IBackgroundJobIdentity
{
public static string JobName => "audit-retention"; // 与 BackgroundJobIdentities 内置身份一致
}
}
// 2. 编写纯粹业务执行器:只依赖领域端口与 AppClock,零 Quartz 依赖
public sealed class AuditRetentionJobExecutor(
IAuditRetentionPort retentionPort,
IAppClock clock) : IJobExecutor<AuditJobIdentities.RetentionPrune>
{
public async Task<Result> ExecuteAsync(CancellationToken ct)
{
// 计算归档保留阈值(清理 180 天前的历史日志)
var cutoffTime = clock.UtcNow.AddDays(-180);
// 调用应用端口执行分批裁剪
await retentionPort.PruneExpiredLogsAsync(cutoffTime, ct);
return Result.Success();
}
}

第二步:在 JobHost 中装配与声明式配置

在 JobHost 启动时,框架读取 appsettings.json 并注册调度规则:

appsettings.json: 声明式任务调度配置
{
"BackgroundJobs": {
"audit-retention": {
"Enabled": true,
"CronExpression": "0 0 2 * * ?",
"IntervalSeconds": 86400
// 覆盖入口只读 CronExpression/IntervalSeconds/Enabled 三键;
// Description 属模块声明层参数,不能被配置覆盖。
// IntervalSeconds 与 CronExpression 互斥,同时给出会 fail-loud。
}
}
}
  • 类型安全绑定:编译期捕获错误,未绑定的任务在启动时直接报错,绝不等到运行时才抛异常;
  • 配置即生效:无需修改 C# 代码即可通过环境变量或配置中心调整 Cron 表达式或临时停用任务。

第三步:执行安全与优雅停机(Graceful Shutdown)

在长时间运行的批处理任务中,必须遵循以下安全准则:

  • 游标分批处理:每次只拉取 1,000 条,处理完毕提交事务并更新游标,杜绝一次性将百万级大表加载到内存;
  • 响应取消信号:在批次循环中检查 cancellationToken.IsCancellationRequested,收到容器终止信号(SIGTERM)时安全退出当前批次,避免数据处于中间悬挂状态。

总结

BitzOrcas 的后台作业构建块消除了传统调度的不确定性:

  • 调度器中立:业务执行器纯净无污染,单元测试毫秒级秒跑;
  • 集群持久化防重:底层基于数据库锁保证同一时刻单实例执行;
  • 全链路可观测:每次执行的耗时、结果与异常自动进入运维大盘。

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%