Quartz.net的最佳实践

  • Quartz.net的最佳实践已关闭评论
  • 252 次浏览
  • A+
所属分类:.NET技术

Quartz.NET 官网

Quartz.net是什么

Quartz.NET 是一个功能齐全的开源作业调度系统,他的前身来源于java的Quartz.

Quartz.net安装和使用

基于visual studio引用安装,其他IDE类似,或者下载DLL手动引用也是可以的;运行环境基于.net core,源.net程序类似
Quartz.net的最佳实践
 

Quartz.net的架构和关键属性以及方法

三个主要的概念

  • scheduler 作业调度,作业计划在给定触发器发生时运行,实际就是领导
  • job 作业,实现简单 IJob 接口的任何 .NET 类,实际就是干活的员工
  • trigger 侦听器,负责捕获调度事件以监视或控制作业,实际就是监工
监工发现员工偷懒了,报告给领导,领导知道后,给员工派了很多活,导致了员工天天996. 大概是这么个关系
 

Quartz.net的一些关键属性

类型
 
ISchedulerFactory
SchedulerBuilder的工厂类
IScheduler
用于与调度程序交互的主要 API
SchedulerBuilder
用于定义/构建调度程序实例,需要 Quartz 3.1 或更高版本
IJobFactory
JobBuilder的工厂类
IJob
由您希望由调度程序执行的组件实现的接口
IJobDetail
用于定义作业的实例
JobBuilder
用于定义/构建 JobDetail 实例,这些实例定义作业的实例
TriggerBuilder
用于定义/构建触发器实例
ITrigger
定义执行给定作业的计划的一个组件,作业可以有多个关联的触发器
ListenerManager
侦听器事件,例如:执行job工作之前,之后触发等等,同时也可用于触发器侦听
 

IServiceCollectionQuartzConfigurator 参数

Scheduler Name
调度作业的名称
Scheduler Id
SchedulerId
Max Batch Size
同时执行job的最大数量
InterruptJobsOnShutdown
 
InterruptJobsOnShutdownWithWait
 
BatchTriggerAcquisitionFireAheadTimeWindow
 
 

在通用host或者webhost中的最佳实践

通用host或者webhost代码是一样的

执行流程

  1. 在通用主机服务中注入服务AddQuartz,AddQuartzHostedService
  2. 在AddQuartz中配置调度作业的基本属性(SchedulerId等等)和调度器以及作业(ScheduleJob,AddJob,AddTrigger);可以在这个地方写入所有的调度作业,也可以写入一个initjob作业,在主机完全启动5秒后执行相应的业务(可规避掉某些依赖服务未启动的问题)
  3. 在initjob中,初始化其他定时任务。官网介绍job只能有一个无参的构造函数,但我亲测可以注入(笑脸)
  4. 关于job和reigger的具体参数,可查看官网

如下

以下代码和执行结果,其中执行顺序一目了然
代码
   static void Main(string[] args)         {             Console.WriteLine("Hello, World!");              LogProvider.SetCurrentLogProvider(new ConsoleLogProvider());             //通用主机配置             var build = Host.CreateDefaultBuilder(args)                 .ConfigureServices((host, services) =>                 {                     Console.WriteLine("--------1");                                          //调度作业的唯一id的唯一标识,用于集群搭建cluster                     q.SchedulerId = "SchedulerId_01";                     //配置Quartz服务                     services.AddQuartz(q =>                     {                         Console.WriteLine("--------2");                         //依赖注入,ISchedulerFactory,Ijob等等                         q.UseMicrosoftDependencyInjectionJobFactory();                          //方法一和方法二使用不同方法的写法,本质基本是一样的                         //方法一                         q.ScheduleJob<InitJob>(                             trigger =>                             {                                 Console.WriteLine("--------33");                                 //WithIdentity 绑定触发器或者job的唯一属性和组                                 //TriggerKey,JobKey 都是代表唯一个属性和组                                 trigger.WithIdentity(new TriggerKey("trigger1", "triggergroup1"))                                        .WithSimpleSchedule(x => x.WithIntervalInSeconds(5))                                        // .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(5)))                                        //  .WithDailyTimeIntervalSchedule(x => x.WithInterval(10, IntervalUnit.Second))                                        .WithDescription("init 描述");                             },                             jobConfigure =>                             {                                 Console.WriteLine("--------44");                                 jobConfigure.WithIdentity(new JobKey("Init1", "jobgroup1"));                             }                         );                          //方法二                         //q.AddJob<InitJob>(opts =>                         //{                         //    Console.WriteLine("--------3");                         //    opts.WithIdentity(new JobKey("Init1", "jobgroup1"));                          //});                          //q.AddTrigger(opts =>                         //{                         //    Console.WriteLine("--------4");                         //    //将job添加至触发器中                         //    opts.ForJob(new JobKey("Init1", "jobgroup1"))                         //    .WithIdentity("trigger1", "triggergroup1")                         //    .WithSimpleSchedule(x =>                         //    {                         //        Console.WriteLine("--------6");                         //        x.WithIntervalInSeconds(5);                         //        //.RepeatForever();                         //        //.WithRepeatCount(5);                         //    });                          //});                      });                     services.AddQuartzHostedService(options =>                     {                             options.WaitForJobsToComplete = true;                     });                  }).Build();              //var schedulerFactory =  build.Services.GetService<ISchedulerFactory>();             //var scheduler = schedulerFactory.GetScheduler();             build.Run();             Console.WriteLine("--------7");         }     }       public class SampleJob : IJob     {         public SampleJob(ISchedulerFactory schedulerFactory, IJobFactory jobFactory)         {             Console.WriteLine("--------8");         }         public async Task Execute(IJobExecutionContext context)         {             Console.WriteLine("--------9");             context.JobDetail.JobDataMap.GetString("我是sample的job数据key");             Console.WriteLine($"我是sample的job数据key: {context.JobDetail.JobDataMap.GetString("我是sample的job数据key")}");             Console.WriteLine($"我是sample的Trigger数据key: {context.MergedJobDataMap.GetString("我是sample的Trigger数据key")}");          }     }     public class InitJob : IJob     {         public ISchedulerFactory _schedulerFactory;         public IJobFactory _jobFactory;         public InitJob(ISchedulerFactory schedulerFactory, IJobFactory jobFactory)         {             Console.WriteLine("--------12");             _schedulerFactory = schedulerFactory;             _jobFactory = jobFactory;         }         public async Task Execute(IJobExecutionContext context)         {             Console.WriteLine("--------13");             Console.WriteLine("InitJob Execute " + Random.Shared.Next(0, 100));                          //创建job             IJobDetail job = JobBuilder.Create<SampleJob>()                                 //写入参数                                 .UsingJobData("我是sample的job数据key", "我是sample的job数据value")                                 .WithIdentity("sample1", "jobgroup1").Build();             //创建触发器             ITrigger trigger = TriggerBuilder.Create()                                    .UsingJobData("我是sample的Trigger数据key", "我是sample的Trigger数据value")                                    .WithIdentity("trigger_sample1", "triggergroup1")                                    .WithDescription("我是描述")                                    //通过corn符号来创建触发器                                    //.WithCronSchedule(taskOptions.CronExpression)                                    .WithSimpleSchedule(x =>                                        x.WithIntervalInSeconds(5) //5秒后执行                                        .RepeatForever()  //重复                                     )                                    .Build();             //通过工厂获取一个作业调度             var scheduler = await _schedulerFactory.GetScheduler();             //绑定一个job的事件侦听器,从执行顺序上看 new JobListen是一个单例类             scheduler.ListenerManager.AddJobListener(new JobListen(), KeyMatcher<JobKey>.KeyEquals(new JobKey("sample1", "jobgroup1")));             //将作业和从触发器绑定至作业调度上             await scheduler.ScheduleJob(job, trigger);             //启动作业调度             await scheduler.Start();              Console.WriteLine("--------14");         }     }     //作业侦听器     public class JobListen : JobListenerSupport     {         public JobListen()         {             Console.WriteLine("--------20");         }         public override string Name { get { return "JobListen20"; } }         //调用job之前执行         public override Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken)         {             Console.WriteLine("--------21");             return base.JobToBeExecuted(context, cancellationToken);         }     }     //日志组件     public class ConsoleLogProvider : ILogProvider     {         public Logger GetLogger(string name)         {             return (level, func, exception, parameters) =>             {                 if (level >= LogLevel.Info && func != null)                 {                     Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters);                 }                 return true;             };         }         public IDisposable OpenNestedContext(string message)         {             throw new NotImplementedException();         }         public IDisposable OpenMappedContext(string key, object value, bool destructure = false)         {             throw new NotImplementedException();         }     }

执行结果
 
Quartz.net的最佳实践