1、nuget包

2、項目中添加三個類

2.1 JobFactory
public class JobFactory : IJobFactory
{
/// <summary>
/// dotnet core 的 ioc
/// </summary>
private readonly IServiceProvider _serviceProvider;
/// <summary>
/// 構造注入
/// </summary>
/// <param name="serviceProvider"></param>
public JobFactory(IServiceProvider serviceProvider)
=> _serviceProvider = serviceProvider;
/// <summary>
/// 按照startup里批量注冊的job,創建一個指定類型的job
/// </summary>
/// <param name="bundle"></param>
/// <param name="scheduler"></param>
/// <returns></returns>
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
var serviceScope = _serviceProvider.CreateScope(); // 獲得一個ioc對象,指定創建scope級別的實例(例如在job里面如果需要依賴注入ef,但是startup里面配置的ef是scope級別的話,這里就必須指定為scope,不然會報錯,因為默認是創建單例,單例和scope線程內唯一是沖突的)。
return serviceScope.ServiceProvider.GetService(bundle.JobDetail.JobType) as IJob; // 手動注入一個 job 后返回
}
public void ReturnJob(IJob job) { }
}
2.2 JobSchedule
/// <summary>
/// 在定義一個定時作業計划時所需要的數據
/// 可以看成一個dto,為job創建schedule時用的
/// </summary>
public class JobSchedule
{
public JobSchedule(Type jobType, string cronExpression)
{
JobType = jobType;
CronExpression = cronExpression;
}
/// <summary>
/// 作業類型
/// </summary>
public Type JobType { get; }
/// <summary>
/// cron 表達式
/// </summary>
public string CronExpression { get; }
}
2.3 QuartzHostedService
/// <summary>
/// quartz 主機服務
/// </summary>
[DisallowConcurrentExecution]
public class QuartzHostedService : IHostedService
{
/// <summary>
/// 定時作業計划生成工廠,這一項在startup有配置集群模式
/// </summary>
private readonly ISchedulerFactory _schedulerFactory;
/// <summary>
/// 定時作業工廠
/// </summary>
private readonly IJobFactory _jobFactory;
/// <summary>
/// 定時作業計划集合,配合dotnet core的ioc注入進來
/// </summary>
private readonly IEnumerable<JobSchedule> _jobSchedules;
/// <summary>
/// 日志
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// quartz scheduler
/// </summary>
private IScheduler _scheduler;
/// <summary>
/// 構造注入
/// </summary>
/// <param name="schedulerFactory"></param>
/// <param name="jobFactory"></param>
/// <param name="jobSchedules"></param>
/// <param name="logger"></param>
public QuartzHostedService(
ISchedulerFactory schedulerFactory,
IJobFactory jobFactory,
IEnumerable<JobSchedule> jobSchedules,
ILogger<QuartzHostedService> logger
)
{
_schedulerFactory = schedulerFactory;
_jobSchedules = jobSchedules;
_jobFactory = jobFactory;
_logger = logger;
}
/// <summary>
/// 批量啟動定時任務
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task StartAsync(CancellationToken cancellationToken)
{
_scheduler = await _schedulerFactory.GetScheduler(cancellationToken);
_scheduler.JobFactory = _jobFactory;
// 循環遍歷startup里注冊的作業
foreach (var jobSchedule in _jobSchedules)
{
var job = CreateJob(jobSchedule);
var trigger = CreateTrigger(jobSchedule);
await _scheduler.ScheduleJob(job, trigger, cancellationToken);
}
await _scheduler.Start();
}
/// <summary>
/// 停止
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task StopAsync(CancellationToken cancellationToken)
=> await _scheduler?.Shutdown(cancellationToken);
/// <summary>
/// 創建定時作業
/// </summary>
/// <param name="schedule"></param>
/// <returns></returns>
private static IJobDetail CreateJob(JobSchedule schedule)
{
return JobBuilder
.Create(schedule.JobType)
.WithIdentity(GenerateIdentity(schedule, IdentityType.Job))
.WithDescription(schedule.CronExpression)
.Build();
}
/// <summary>
/// 創建觸發器
/// </summary>
/// <param name="schedule"></param>
/// <returns></returns>
private static ITrigger CreateTrigger(JobSchedule schedule)
{
return TriggerBuilder
.Create()
.WithIdentity(GenerateIdentity(schedule, IdentityType.Trigger))
.WithCronSchedule(schedule.CronExpression)
.WithDescription(schedule.JobType.FullName)
.Build();
}
/// <summary>
/// 生成一個標識(類似主鍵的意思)
/// </summary>
/// <param name="schedule"></param>
/// <param name="identityType">標識類型,一個job作業,或者是trigger觸發器</param>
/// <returns></returns>
private static string GenerateIdentity(JobSchedule schedule, IdentityType identityType)
{
switch (identityType)
{
case IdentityType.Job:
return $"NdcPayInternal_Job_{schedule.JobType.Name}";
case IdentityType.Trigger:
return $"NdcPayInternal_Trigger_{schedule.JobType.Name}";
}
return schedule.JobType.FullName;
}
/// <summary>
/// 標識類型
/// </summary>
private enum IdentityType
{
Job,
Trigger
}
}
3、startup里面注冊一下上面三個

#region quartz
services.AddHostedService<QuartzHostedService>();
services.AddSingleton<IJobFactory, JobFactory>();
services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
#endregion
4、上面三步就已經是配置好了 Quartz ,接下來創建兩個 job

4.1 創建 MyJob1 和 MyJob2
public class MyJob1 : IJob
{
/// <summary>
/// 日志
/// </summary>
private readonly ILogger _logger;
public MyJob1(ILogger<MyJob1> logger)
=> _logger = logger;
public Task Execute(IJobExecutionContext context)
{
_logger.LogInformation("執行了我,我是 【job1】");
return Task.CompletedTask;
}
}
public class MyJob2 : IJob
{
/// <summary>
/// 日志
/// </summary>
private readonly ILogger _logger;
public MyJob2(ILogger<MyJob2> logger)
=> _logger = logger;
public Task Execute(IJobExecutionContext context)
{
_logger.LogInformation("執行了我,我是 【job2】");
return Task.CompletedTask;
}
}
4.2 在startup中注冊這兩個 job

services.AddTransient<MyJob1>();
services.AddTransient(u => new JobSchedule(
jobType: typeof(MyJob1),
cronExpression: "0/10 * * * * ?")); // 10s執行一次
services.AddTransient<MyJob2>();
services.AddTransient(u => new JobSchedule(
jobType: typeof(MyJob2),
cronExpression: "0/15 * * * * ?")); // 15s執行一次
運行之后:

以上就是單機版的定時任務構建,下一篇文章會基於此,升級為高可用的Quzrtz集群。