You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET7.0 Core中Quartz多DI定时任务重复执行问题求助

问题根源分析
  1. 重复Scheduler实例导致JobFactory被覆盖:你每个任务的调度方法都调用了StdSchedulerFactory.GetScheduler(),默认情况下Quartz会返回同一个Scheduler实例(未指定不同实例名)。第二个任务设置的CronJobBJobFactory会覆盖第一个任务设置的CronJobAJobFactory,导致所有触发器触发时,都会用最后设置的工厂创建Job。
  2. 专属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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 08:35:38