quartz.net 必须通过 adojobstore 实现持久化,将任务、触发器等存入数据库以支持重启恢复和集群;需正确配置连接字符串、方言(如 sqlserverdelegate)、建表脚本(官方提供),否则默认回退至内存模式导致任务丢失。

Quartz.NET 用什么方式持久化任务
Quartz.NET 本身不自带数据库存储,必须通过 AdoJobStore 实现持久化。它把触发器(Trigger)、任务(JobDetail)、调度状态等写入数据库表,重启后自动恢复未执行/正在等待的任务。不配 AdoJobStore 就是纯内存模式,进程一关,所有任务全丢。
关键点:不是“选配”,而是“必配”——只要要求任务不丢失,就必须启用 AdoJobStore,且不能只改配置,还要建表、配连接字符串、禁用 RAMJobStore。
-
AdoJobStore是唯一支持事务、集群、恢复的持久化方案;RAMJobStore(默认)完全在内存里,关机即清空 - 必须使用支持事务的数据库(SQL Server / PostgreSQL / MySQL / Oracle),SQLite 不推荐用于生产(并发锁不可靠)
- 表结构不能手写,必须用 Quartz 官方提供的 SQL 脚本生成,不同版本脚本不兼容(比如 3.7 和 3.8 的
QRTZ_JOB_LISTENERS表已移除)
怎么配 AdoJobStore 连接字符串和方言
Quartz 需要明确知道你用什么数据库、怎么连、怎么生成 SQL。这靠两个核心配置项:quartz.jobStore.type 和 quartz.jobStore.driverDelegateType,漏一个就会回退到内存模式或启动失败。
以 SQL Server 为例,典型配置如下(.NET 6+ Program.cs 或 appsettings.json):
var properties = new NameValueCollection
{
["quartz.scheduler.instanceName"] = "MyScheduler",
["quartz.threadPool.threadCount"] = "5",
["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz",
["quartz.jobStore.dataSource"] = "default",
["quartz.jobStore.tablePrefix"] = "QRTZ_",
["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz",
["quartz.dataSource.default.connectionString"] = "Server=.;Database=QuartzDb;Trusted_Connection=true;",
["quartz.dataSource.default.provider"] = "SqlServer"
};
-
quartz.jobStore.driverDelegateType必须匹配数据库类型:SqlServerDelegate、StdAdoDelegate(通用)、PostgreSQLDelegate等,拼错会报Cannot instantiate class -
quartz.dataSource.default.provider决定 ADO.NET Provider,SQL Server 填SqlServer,MySQL 填MySql(需引用Quartz.Plugins对应包) - 连接字符串里不要加
MultipleActiveResultSets=True(除非真需要),否则可能引发Invalid operation. The connection is closed.
建表脚本从哪来?能不能自己改表结构
Quartz 官方 GitHub 的 src\storage\adonet\tables_*.sql 是唯一可信来源。NuGet 包里不带脚本,也不能靠 EF Core 迁移生成——Quartz 的表有特殊约束(如复合主键、特定索引、tinyint 字段语义),EF 无法还原。
例如 Quartz 3.7 对应的 SQL Server 脚本路径是:https://github.com/quartznet/quartznet/blob/v3.7.0/src/storage/ado/tables_sqlserver.sql。下载后直接在目标库执行即可。
- 表名前缀(
QRTZ_)必须和配置中quartz.jobStore.tablePrefix一致,否则查不到表,日志里反复报Table 'QRTZ_TRIGGERS' not found - 千万别手动删
QRTZ_PAUSED_TRIGGER_GRPS或改QRTZ_FIRED_TRIGGERS的字段类型——这些表由 Quartz 内部维护,乱改会导致状态混乱甚至死锁 - 如果用的是 Azure SQL,注意关闭
quartz.jobStore.useProperties = true(默认 false),否则可能因Properties字段超长报错
为什么任务没恢复?常见启动失败信号
配完不生效,90% 是因为 Scheduler 启动时已静默 fallback 到 RAMJobStore。看日志最准:搜 Using default implementation for ThreadExecutor 后面是否跟了 JobStoreTX —— 如果是 RAMJobStore,说明配置没生效。
- 检查
ISchedulerFactory.GetScheduler()是否用了你传入的properties,而不是空参构造(空参会走默认内存配置) - SQL Server 用户注意:数据库用户必须有
db_datareader+db_datawriter角色,仅public权限会导致插入QRTZ_SCHEDULER_STATE失败,但错误被吞掉 - 集群场景下必须设
quartz.jobStore.isClustered = true,否则多实例会互相覆盖FIRE_INSTANCE_ID,任务重复触发或卡住 - 首次启动时若表为空,
AdoJobStore不会报错,但后续添加任务后务必调用await scheduler.Start(),否则任务不会真正注册进存储
持久化的关键不在“存进去”,而在“取出来并正确重建状态”。哪怕表里数据齐全,只要 JobDetail 类型名或程序集路径变了(比如重命名命名空间),反序列化就会失败,对应任务永久挂起——这个细节几乎没人检查,但线上最容易出问题。










