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集群。