Quartz.net的最佳实践
Quartz.NET 官网
Quartz.net是什么
Quartz.NET 是一个功能齐全的开源作业调度系统,他的前身来源于java的Quartz.
Quartz.net安装和使用
基于visual studio引用安装,其他IDE类似,或者下载DLL手动引用也是可以的;运行环境基于.net core,源.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代码是一样的
执行流程
- 在通用主机服务中注入服务AddQuartz,AddQuartzHostedService
- 在AddQuartz中配置调度作业的基本属性(SchedulerId等等)和调度器以及作业(ScheduleJob,AddJob,AddTrigger);可以在这个地方写入所有的调度作业,也可以写入一个initjob作业,在主机完全启动5秒后执行相应的业务(可规避掉某些依赖服务未启动的问题)
- 在initjob中,初始化其他定时任务。官网介绍job只能有一个无参的构造函数,但我亲测可以注入(笑脸)
- 关于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的增删改查(新增删除添加任务)
internal class Program { static void Main(string[] args) { var host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { services.AddQuartz(service => { service.UseMicrosoftDependencyInjectionJobFactory(); service.SchedulerId = "SchedulerId"; }); services.AddQuartzHostedService(service => { service.WaitForJobsToComplete = true; }); services.AddHostedService<Worker>(); }) .Build(); host.Run(); } } public static class QuartzHelper { public static void Start<T>(TaskOptions taskOptions, ISchedulerFactory schedulerFactory, IJobFactory jobFactory) where T : class, IJob, new() { Triiger<T>(JobAction.开启, taskOptions, schedulerFactory, jobFactory); } public static async void Add<T>(TaskOptions taskOptions, ISchedulerFactory schedulerFactory, IJobFactory jobFactory) where T:class,IJob,new() { IJobDetail job = JobBuilder.Create<T>() .WithIdentity(new JobKey(taskOptions.TaskName, taskOptions.GroupName)).Build(); ITrigger trigger = TriggerBuilder.Create() .WithIdentity(new TriggerKey(taskOptions.TaskName, taskOptions.GroupName)) .WithDescription(taskOptions.Describe) .WithCronSchedule(taskOptions.CronExpression) .Build(); IScheduler scheduler = null; if (string.IsNullOrEmpty(taskOptions.InstanceName) && string.IsNullOrEmpty(taskOptions.InstanceId)) { //从工厂获取调度中心,获取的是一个单例调度中心,对单一的调度中心操作会影响全局的调度,比如:scheduler.stop() 会停止掉所有的调度中心 //如果需要分别控制,需要创建自定义的调度中心,如下: //创建自定义的调度中心 var collection = new System.Collections.Specialized.NameValueCollection(); collection.Add("quartz.scheduler.instanceName", taskOptions.InstanceName); collection.Add("quartz.scheduler.instanceId", taskOptions.InstanceId); ISchedulerFactory schedulerFactory2 = new StdSchedulerFactory(collection); scheduler = await schedulerFactory2.GetScheduler(); } else { scheduler = await schedulerFactory.GetScheduler(); } await scheduler.ScheduleJob(job, trigger); await scheduler.Start(); } public static async void Triiger<T>(JobAction jobAction, TaskOptions taskOptions, ISchedulerFactory schedulerFactory, IJobFactory jobFactory) where T : class, IJob, new() { IScheduler scheduler = await schedulerFactory.GetScheduler(); //获取指定组下所有job List<JobKey> jobKeys = scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(taskOptions.GroupName)).Result.ToList(); //从该组中获取包含触发器名称的job JobKey jobKey = jobKeys.Where(s => scheduler.GetTriggersOfJob(s).Result.Any(x => (x as CronTriggerImpl).Name == taskOptions.TaskName)).FirstOrDefault(); //获取当前触发器 var triggers = await scheduler.GetTriggersOfJob(jobKey); ITrigger trigger = triggers?.Where(x => (x as CronTriggerImpl).Name == taskOptions.TaskName).FirstOrDefault(); switch (jobAction) { case JobAction.删除: await scheduler.PauseTrigger(trigger.Key); //暂停 await scheduler.UnscheduleJob(trigger.Key);// 移除触发器 await scheduler.DeleteJob(trigger.JobKey); //删除job break; case JobAction.更新: //先删除,再添加 await scheduler.PauseTrigger(trigger.Key); await scheduler.UnscheduleJob(trigger.Key);// 移除触发器 await scheduler.DeleteJob(trigger.JobKey); Add<T>(taskOptions, schedulerFactory, jobFactory); break; case JobAction.暂停: await scheduler.PauseTrigger(trigger.Key); break; case JobAction.开启: await scheduler.ResumeTrigger(trigger.Key); break; case JobAction.立即执行: await scheduler.TriggerJob(jobKey); break; } } } public class TaskOptions { public string Id { get; set; } public string TaskName { get; set; } public string GroupName { get; set; } public string Describe { get; set; } public string CronExpression { get; set; } public string InstanceName { get; set; } public string InstanceId { get; set; } } public enum JobAction { 开启, 暂停, 删除, 更新, 立即执行 } public class Job : IJob { public Task Execute(IJobExecutionContext context) { throw new NotImplementedException(); } } public class Worker : IHostedService { public ISchedulerFactory _schedulerFactory { get; set; } public IJobFactory _jobFactory { get; set; } public Worker(ISchedulerFactory schedulerFactory, IJobFactory jobFactory) { _schedulerFactory = schedulerFactory; _jobFactory = jobFactory; } Task IHostedService.StartAsync(CancellationToken cancellationToken) { QuartzHelper.Add<Job>(new TaskOptions() { CronExpression = "0/10 * * * * ?", GroupName = "GroupName", TaskName = "TaskName" }, _schedulerFactory, _jobFactory); return Task.CompletedTask; } Task IHostedService.StopAsync(CancellationToken cancellationToken) { throw new NotImplementedException(); } }
本文作者:anekos
本文链接:https://www.cnblogs.com/workcn/p/17491550.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步