最近有面试!都有问道Quartz方面的问题,之前的项目有使用过,也知道怎么用,但面试时要说出它的原理,一时半会还真说不来!查阅了一些资料先记录下来吧
Quartz.NET官网地址:https://www.quartz-scheduler.net/
Quartz.NET文档地址:
https://www.quartz-scheduler.net/documentation/index.html
Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中。
它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,支持cron-like表达式等等。
现在Quartz.NET3.0已支持Asp.Net Core,3.0新功能如下:
新功能
-
具有异步/等待支持的基于任务的作业,内部以异步/等待方式工作
-
支持.NET Core / netstandard 2.0和.NET Framework 4.5.2及更高版本
-
通过提供程序名称SQLite-Microsoft支持Microsoft.Data.Sqlite,旧的提供程序SQLite也仍然有效
-
增加了SQL Server内存优化表和
Quartz.Impl.AdoJobStore.UpdateLockRowSemaphoreMOT的初步支持
-
Common.Logging从相关性中删除
-
从ILMerge进程中删除的C5集合不再需要
-
在插件启动时添加对作业调度XML文件的急切验证的支持
-
在TimeZoneUtil中添加对额外的自定义时区解析器功能的支持
变化
-
作业和插件现在位于独立的程序集NuGet包Quartz.Jobs和Quartz.Plugins中
-
ADO.NET提供者名称已被简化,提供者名称没有版本,例如SqlServer-20 => SqlServer
-
API方法已被重新使用,主要使用IReadOnlyCollection,这隐藏了两个HashSets和List小号
-
LibLog一直隐藏于内部(ILog等),就像它原本打算的那样
-
SimpleThreadPool消失了,旧的拥有的线程消失了
-
调度程序方法已更改为基于任务,请记住等待它们
-
IJob接口现在返回一个任务\
-
一些IList属性已更改为IReadOnlyList以正确反映意图
-
SQL Server CE支持已被删除
-
DailyCalendar现在将日期时间用于排除的日期,并具有ISet接口来访问它们
-
IObjectSerializer有新的方法,void Initialize(),必须实现
-
IInterruptableJob取消了上下文的CancellationToken
Quartz API的关键接口和类是:
-
IScheduler - 与调度程序交互的主要API。
-
IJob - 您希望由调度程序执行的组件实现的接口。
-
IJobDetail - 用于定义作业的实例。
-
ITrigger - 定义执行给定Job的时间表的组件。
-
JobBuilder - 用于定义/构建定义作业实例的JobDetail实例。
-
TriggerBuilder - 用于定义/构建触发器实例
一、Quartz.NET基本使用
1、新建Asp.Net Core 项目,使用NuGet添加Quartz,或使用程序包管理器引用,命令如下:
Install-Package Quartz
2、简单实例,代码如下:
using Five.QuartzNetJob.ExecuteJobTask.Service; using Quartz; using Quartz.Impl; using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Text; using System.Threading.Tasks; namespace Five.QuartzNetJob.Web.Controllers { public class TestTask { public async Task StartTestAsync() { try { // 从工厂中获取调度程序实例 NameValueCollection props = new NameValueCollection { { "quartz.serializer.type", "binary" } }; StdSchedulerFactory factory = new StdSchedulerFactory(props); IScheduler scheduler = await factory.GetScheduler(); // 开启调度器 await scheduler.Start(); // 定义这个工作,并将其绑定到我们的IJob实现类 IJobDetail job = JobBuilder.Create<HelloJob>() .WithIdentity("job1", "group1") .Build(); // 触发作业立即运行,然后每10秒重复一次,无限循环 ITrigger trigger = TriggerBuilder.Create() .WithIdentity("trigger1", "group1") .StartNow() .WithSimpleSchedule(x => x .WithIntervalInSeconds(10) .RepeatForever()) .Build(); // 告诉Quartz使用我们的触发器来安排作业 await scheduler.ScheduleJob(job, trigger); // 等待60秒 await Task.Delay(TimeSpan.FromSeconds(60)); // 关闭调度程序 await scheduler.Shutdown(); } catch (SchedulerException se) { await Console.Error.WriteLineAsync(se.ToString()); } } } }
HelloJob内容如下:
using Quartz; using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; namespace Five.QuartzNetJob.ExecuteJobTask.Service { public class HelloJob : IJob { public Task Execute(IJobExecutionContext context) { Console.Out.WriteLineAsync("Greetings from HelloJob!"); return Task.CompletedTask; } } }
执行效果如下:
注:Quartz的版本3.0.3中删除了IJob实现的异地调用,也就是不支持async、await异步调用,3.0.2版本支持异步调用。
二、触发器类型
1、SimpleTrigger触发器(简单触发器)
SimpleTrigger的属性包括:开始时间和结束时间,重复计数和重复间隔。重复计数可以是零,一个正整数或常数值SimpleTrigger.RepeatIndefinitely。重复时间间隔属性必须是TimeSpan.Zero或正的TimeSpan值。请注意,重复间隔为0会导致触发器的“重复计数”触发同时发生。
SimpleTrigger实例使用TriggerBuilder(用于触发器的主属性)和WithSimpleSchedule扩展方法(用于SimpleTrigger特定的属性)构建。
在特定的时间内建立触发器,无需重复,代码如下:
// 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create() .WithIdentity("trigger1", "group1") .StartAt(DateTime.Now) //指定开始时间为当前系统时间 .ForJob("job1", "group1") //通过JobKey识别作业 .Build();
在特定的时间建立触发器,然后每十秒钟重复十次:
// 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger ITrigger trigger = trigger = TriggerBuilder.Create() .WithIdentity("trigger2", "group2") .StartAt(DateTime.Now) // 指定开始时间 .WithSimpleSchedule(x => x .WithIntervalInSeconds(10) .WithRepeatCount(10)) // 请注意,重复10次将总共重复11次 .ForJob("job2", "group2") //通过JobKey识别作业 .Build();
构建一个触发器,将在未来五分钟内触发一次:
// 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger ITrigger trigger = trigger = (ISimpleTrigger)TriggerBuilder.Create() .WithIdentity("trigger3", "group3") .StartAt(DateBuilder.FutureDate(5, IntervalUnit.Minute)) //使用DateBuilder将来创建一个时间日期 .ForJob("job3", "group3") //通过JobKey识别作业 .Build();
建立一个现在立即触发的触发器,然后每隔五分钟重复一次,直到22:00:
// 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger ITrigger trigger = trigger = TriggerBuilder.Create() .WithIdentity("trigger4", "group4") .WithSimpleSchedule(x => x .WithIntervalInMinutes(5)//每5秒执行一次 .RepeatForever()) .EndAt(DateBuilder.DateOf(22, 0, 0))//晚上22点结束 .Build();
建立一个触发器,在一个小时后触发,然后每2小时重复一次:
// 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger ITrigger trigger = TriggerBuilder.Create() .WithIdentity("trigger5") // 由于未指定组,因此“trigger5”将位于默认分组中 .StartAt(DateBuilder.EvenHourDate(null)) // 获取下个一小时时间 .WithSimpleSchedule(x => x .WithIntervalInHours(2)//执行间隔2小时 .RepeatForever()) .Build();
因此简单的任务调度使用SimpleTrigger完全够用,如果SimpleTrigger还是不能满足您的需求请往下看。
2、CronTrigger触发器
如果你需要一个基于类似日历的概念而不是精确指定的SimpleTrigger时间间隔的工作调度计划,CronTriggers通常比SimpleTrigger更有用。
使用CronTrigger,您可以在每周一,周三的上午9点至上午10点之间指定开始时间表,例如“每星期五中午”或“每个工作日和上午9点30分”,或者“每5分钟”和星期五”。
即使如此,就像SimpleTrigger一样,CronTrigger有一个startTime,它指定了时间表的生效时间,还有一个(可选的)endTime,用于指定应该停止时间表的时间。
这里不在详细介绍Cron。
Cron表达式在线生成器:http://cron.qqe2.com/
Cron表达式详细介绍:https://www.jianshu.com/p/e9ce1a7e1ed1
每天早上8点到下午5点建立一个触发器,每隔一分钟就会触发一次:
// 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger ITrigger trigger = TriggerBuilder.Create() .WithIdentity("Job1", "group1") .WithCronSchedule("0 0/2 8-17 * * ?")//使用Cron表达式 .ForJob("Job1", "group1") .Build();
建立一个触发器,每天在上午10:42开始执行:
// 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger ITrigger trigger = TriggerBuilder.Create() .WithIdentity("Job2", "group2") .WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(10, 42)) // 在这里使用CronScheduleBuilder的静态辅助方法 .ForJob("Job2", "group2") .Build();
构建一个触发器,将在星期三上午10:42在除系统默认值之外的TimeZone中触发:
// 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger ITrigger trigger = TriggerBuilder.Create() .WithIdentity("Job3", "group3") .WithCronSchedule("0 42 10 ? * WED", x => x .InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Central America Standard Time"))) .ForJob("Job3", "group3") .Build();
总结: Quartz.NET的3.0版本跟之前的版本api接口变化并不大。只是在3.0版本中添加了异步调用,并支持.net core。简单的任务调度使用官网中的实例即可满足需求。