搭建基于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,
}
現在添加一個任務,建立任務類 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的全部内容,僅用于入門參考。對于其他定時用法、以及各種比較飄的使用,各位大佬可以自行變種。如果有什麼建議或意見,也歡迎留言~~
歡迎加入QQ群:
群号:1079830632