搭建基於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); } } }
新建一個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, }
現在新增一個任務,新建任務類 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(); } }
切回QuartzJobService,在 AddQuartzJobService 方法的最下方,新增上面啟動服務的註冊:
最後,在啟動專案裡面,新增對Wsk.CoreQuartz專案的引用,然後在WskService服務類下,新增對AddQuartzJobService服務的註冊:
啟動專案,看看效果:
由此可見,我們設定的每秒一次觸發效果達成。為了檢驗是不是可以避免同一個排程任務產生併發,在排程任務方法裡面,設定一個延時,看看效果:
執行結果:
說明在當前任務還沒有完成的情況下,不會重複進入。如果要允許重複進,只需要把類上面的DisallowConcurrentExecution 標籤註釋掉就可以。
現在還原回去,然後在Cron表示式改寫成定時10秒,看看效果:
執行結果:
以上就是本篇使用QuartzNet的全部內容,僅用於入門參考。對於其他定時用法、以及各種比較飄的使用,各位大佬可以自行變種。如果有什麼建議或意見,也歡迎留言~~