.net 5中使用Quartz构建单机版定时任务器

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

上述内容代码:https://github.com/book12138/QuartzSample

原文地址:https://www.cnblogs.com/shapman/p/14218440.html