.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/shapmanLv/QuartzSample


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM