.NET7.0 Core中Quartz多DI定时任务重复执行问题求助
问题根源分析
- 重复Scheduler实例导致JobFactory被覆盖:你每个任务的调度方法都调用了
StdSchedulerFactory.GetScheduler(),默认情况下Quartz会返回同一个Scheduler实例(未指定不同实例名)。第二个任务设置的CronJobBJobFactory会覆盖第一个任务设置的CronJobAJobFactory,导致所有触发器触发时,都会用最后设置的工厂创建Job。 - 专属JobFactory硬编码问题:每个JobFactory都硬编码返回特定Job类型(比如
CronJobAJobFactory只返回CronJobAJob),完全忽略了当前触发的Job类型,这也是导致任务执行混乱的核心原因。
修复方案
1. 替换专属JobFactory为通用工厂
创建一个通用的JobFactory,根据当前触发的Job类型从DI容器动态获取实例:
using Quartz; using Quartz.Spi; namespace MyApp.Jobs { public class GenericJobFactory : IJobFactory { private readonly IServiceProvider _serviceProvider; public GenericJobFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) { // 根据当前要执行的Job类型从DI容器获取对应实例 return _serviceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob; } public void ReturnJob(IJob job) { if (job is IDisposable disposable) { disposable.Dispose(); } } } }
2. 重构调度逻辑,使用单一Scheduler实例
将两个任务的调度逻辑合并,只初始化一次Scheduler,统一注册所有任务:
static async Task ScheduleCronJobs(string connectionString) { IServiceProvider serviceProvider = BuildServiceProvider(connectionString); // 只初始化一次Scheduler NameValueCollection props = new NameValueCollection { { "quartz.serializer.type", "binary" } }; StdSchedulerFactory factory = new StdSchedulerFactory(props); IScheduler sched = await factory.GetScheduler(); // 设置通用JobFactory sched.JobFactory = new GenericJobFactory(serviceProvider); await sched.Start(); // 注册JobA var jobA = JobBuilder.Create<JobA>() // 注意:这里要和你的实际Job类名匹配 .WithIdentity("cronJobA", "group1") .Build(); var triggerA = TriggerBuilder.Create() .WithIdentity("cronJobATrigger", "group1") .StartAt(DateTime.Now.AddSeconds(5)) .WithSimpleSchedule(x => x .WithIntervalInSeconds(10) .RepeatForever()) .Build(); await sched.ScheduleJob(jobA, triggerA); // 注册JobB var jobB = JobBuilder.Create<JobB>() // 注意:这里要和你的实际Job类名匹配 .WithIdentity("cronJobB", "group1") .Build(); var triggerB = TriggerBuilder.Create() .WithIdentity("cronJobBTrigger", "group2") .StartAt(DateTime.Now.AddSeconds(7)) .WithSimpleSchedule(x => x .WithIntervalInSeconds(10) .RepeatForever()) .Build(); await sched.ScheduleJob(jobB, triggerB); }
3. 清理冗余代码
删除原来的CronJobAJobFactory和CronJobBJobFactory,这两个专属工厂已经不需要了。
关键修复点说明
- 单一Scheduler实例:避免重复创建/覆盖Scheduler的配置,所有任务都注册到同一个Scheduler中,保证触发器和Job的映射关系正确。
- 通用JobFactory:根据触发的Job类型动态从DI容器获取实例,彻底解决硬编码导致的Job类型错误问题。
内容的提问来源于stack exchange,提问作者random
相关产品推荐
相关产品推荐

