Quartz 3.x切换至AdoJobStore后Trigger持续处于WAITING状态求助
核心问题:调度器被提前关闭
你的代码中存在一个致命逻辑错误:在调用scheduler.Start()后立刻执行了scheduler.Shutdown(waitForJobsToComplete:true),导致调度器刚启动就进入关闭流程。
RAMJobStore是内存级存储,任务触发速度极快,可能在关闭前完成执行;但AdoJobStore需要先将任务、触发器持久化到数据库,这个过程有延迟,调度器还没来得及触发任务就被终止,最终Trigger一直停留在WAITING状态。
配置项检查
Quartz表结构初始化
确认SQL Server中已通过Quartz官方提供的SQL Server建表脚本创建了所有QRTZ_前缀的表,且当前数据库用户拥有读写这些表的权限。表前缀配置
检查quartz.jobStore.tablePrefix的值db_quartz.QRTZ_:其中db_quartz是否是你实际使用的Schema名称(SQL Server默认Schema为dbo),如果Schema不匹配,Quartz会找不到对应表。锁处理器配置
对于SQL Server,推荐将quartz.jobStore.lockHandler.type改为Quartz.Impl.AdoJobStore.StdRowLockSemaphore, Quartz,UpdateLockRowSemaphore在部分SQL Server环境下可能引发锁竞争问题,导致任务无法正常触发。数据源连接验证
确认AnvilPropertyString对应的连接字符串能正常连接到SQL Server,且连接用户拥有足够的数据库操作权限。JobDataMap类型检查
由于quartz.jobStore.useProperties设为true,确保JobDataMap中仅存储字符串、数值等简单可序列化类型,你的代码中UsingJobData("NextJobName", "SendMonthlyInvoices")符合要求,但要保证Job类本身没有不可序列化的属性。
代码逻辑优化
移除即时Shutdown调用
调度器需要保持运行状态才能触发任务:- 如果是控制台程序,可在
scheduler.Start()后添加Console.ReadLine()阻塞主线程; - 如果是Web应用,需将调度器托管在后台服务中,避免提前关闭。
- 如果是控制台程序,可在
修正Job存在性检查逻辑
当前代码中检查job3存在就删除job1的逻辑不合理,改为检查目标Job本身:bool checkWhetherJobExists = await scheduler.CheckExists(new JobKey("job1", "group1")); if (checkWhetherJobExists) { await scheduler.DeleteJob(new JobKey("job1", "group1")); }确认Job类实现
确保MonthlyInvoicing和SendMonthlyInvoices正确实现IJob接口,且Execute方法无未捕获异常:public class MonthlyInvoicing : IJob { public async Task Execute(IJobExecutionContext context) { // 任务业务逻辑 await Task.CompletedTask; } }调整任务链监听器添加时机
将JobChainingJobListener的添加放在Job注册之后,避免链接触发失效:await scheduler.ScheduleJob(job, trigger); await scheduler.AddJob(job2, true); JobChainingJobListener jobchain = new JobChainingJobListener("MyJobListener"); jobchain.AddJobChainLink(new JobKey("job1", "group1"), new JobKey("job3", "group1")); scheduler.ListenerManager.AddJobListener(jobchain);
内容的提问来源于stack exchange,提问作者Samuel Kamau

