十七、.net core(.NET 6)搭建基於Quartz組件的定時調度任務
搭建基於Quartz組件的定時調度任務
先在package包項目下,添加Quartz定時器組件:
新建類庫項目Wsk.Core.QuartzNet,並且引用包類庫項目。然後新建一個中間調度類,叫QuartzMiddleJob:
中間Job源碼:


public class QuartzMiddleJob : IJob { private readonly IServiceProvider _serviceProvider; public QuartzMiddleJob(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public async Task Execute(IJobExecutionContext context) { using (var scope = _serviceProvider.CreateScope()) { var jobType = context.JobDetail.JobType; var job = scope.ServiceProvider.GetRequiredService(jobType) as IJob; await job.Execute(context); } } }
View Code
新建一個Job工廠類,叫WeskyJobFactory,用來獲取剛剛創建的中間調度類的服務:
新建一個通用執行計劃類,叫WeskyJobSchedule,用於每次任務都通過該計划進行生成:
計劃類和枚舉源碼:


public class WeskyJobSchedule { public WeskyJobSchedule(Type jobType, string cronExpression) { this.JobType = jobType ?? throw new ArgumentNullException(nameof(jobType)); CronExpression = cronExpression ?? throw new ArgumentNullException(nameof(cronExpression)); } /// <summary> /// Job類型 /// </summary> public Type JobType { get; private set; } /// <summary> /// Cron表達式 /// </summary> public string CronExpression { get; private set; } /// <summary> /// Job狀態 /// </summary> public JobStatus JobStatu { get; set; } = JobStatus.Init; } /// <summary> /// 運行狀態 /// </summary> public enum JobStatus : byte { [Description("Initialization")] Init = 0, [Description("Running")] Running = 1, [Description("Scheduling")] Scheduling = 2, [Description("Stopped")] Stopped = 3, }
View Code
現在添加一個任務,新建任務類 MyJobs,並且繼承自IJob,然後在Excute方法裡面,就是該任務執行調度時候會進去執行的了:
似乎上面哪兒感覺不太對,咱們把原來的Job工廠裡面到程式碼稍微調整下如下:
NewJob源碼:
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) { return _serviceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob; }
現在新增一個靜態類QuartzJobService,用來當做調度任務的中間啟動項,並且把有關的一些服務註冊進來:
對應源碼:
public static class QuartzJobService { public static void AddQuartzJobService(this IServiceCollection services) { if (services == null) { throw new ArgumentNullException(nameof(services)); } services.AddSingleton<IJobFactory, WeskyJobFactory>(); services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>(); services.AddSingleton<QuartzMiddleJob>(); services.AddSingleton<MyJobs>(); services.AddSingleton( new WeskyJobSchedule(typeof(MyJobs), "0/1 * * * * ? ") ); services.AddHostedService<WeskyJobHostService>(); } }
最後,還少了個啟動項,用來程式啟動的時候,進行啟動定時調度任務。新建類 WeskyJobHostService ,並且新建創建調度任務方法 CreateJob和觸發器方法CreateTrigger:
然後,在開始和結束方法內:
以上源碼如下:


public class WeskyJobHostService: IHostedService { private readonly ISchedulerFactory _schedulerFactory; private readonly IJobFactory _jobFactory; private readonly IEnumerable<WeskyJobSchedule> _jobSchedules; public WeskyJobHostService(ISchedulerFactory schedulerFactory, IJobFactory jobFactory, IEnumerable<WeskyJobSchedule> jobSchedules) { _schedulerFactory = schedulerFactory ?? throw new ArgumentNullException(nameof(schedulerFactory)); _jobFactory = jobFactory ?? throw new ArgumentNullException(nameof(jobFactory)); _jobSchedules = jobSchedules ?? throw new ArgumentNullException(nameof(jobSchedules)); } public IScheduler Scheduler { get; set; } public async Task StartAsync(CancellationToken cancellationToken) { Scheduler = await _schedulerFactory.GetScheduler(cancellationToken); Scheduler.JobFactory = _jobFactory; foreach (var jobSchedule in _jobSchedules) { var job = CreateJob(jobSchedule); var trigger = CreateTrigger(jobSchedule); await Scheduler.ScheduleJob(job, trigger, cancellationToken); jobSchedule.JobStatu = JobStatus.Scheduling; } await Scheduler.Start(cancellationToken); foreach (var jobSchedule in _jobSchedules) { jobSchedule.JobStatu = JobStatus.Running; } } public async Task StopAsync(CancellationToken cancellationToken) { await Scheduler?.Shutdown(cancellationToken); foreach (var jobSchedule in _jobSchedules) { jobSchedule.JobStatu = JobStatus.Stopped; } } private static IJobDetail CreateJob(WeskyJobSchedule schedule) { var jobType = schedule.JobType; return JobBuilder .Create(jobType) .WithIdentity(jobType.FullName) .WithDescription(jobType.Name) .Build(); } private static ITrigger CreateTrigger(WeskyJobSchedule schedule) { return TriggerBuilder .Create() .WithIdentity($"{schedule.JobType.FullName}.trigger") .WithCronSchedule(schedule.CronExpression) .WithDescription(schedule.CronExpression) .Build(); } }
View Code
切回QuartzJobService,在 AddQuartzJobService 方法的最下方,添加上面啟動服務的註冊:
最後,在啟動項目裡面,添加對Wsk.CoreQuartz項目的引用,然後在WskService服務類下,添加對AddQuartzJobService服務的註冊:
啟動項目,看看效果:
由此可見,我們設置的每秒一次觸發效果達成。為了檢驗是不是可以避免同一個調度任務產生並發,在調度任務方法裡面,設置一個延時,看看效果:
運行結果:
說明在當前任務還沒有完成的情況下,不會重複進入。如果要允許重複進,只需要把類上面的DisallowConcurrentExecution 標籤注釋掉就可以。
現在還原回去,然後在Cron表達式改寫成定時10秒,看看效果:
運行結果:
以上就是本篇使用QuartzNet的全部內容,僅用於入門參考。對於其他定時用法、以及各種比較飄的使用,各位大佬可以自行變種。如果有什麼建議或意見,也歡迎留言~~