借鑒:
https://blog.csdn.net/lordwish/article/details/78926252
在最近的一篇文章中講到了如何在web API中實現定時處理,采用的是比較原始的Timer定時器,功能簡單,無法勝任復雜任務。本次就着重介紹一下定時任務框架Quartz.Net。
Quartz.Net來源於Java中的Quartz框架,后來有了.Net版本就加了后綴.Net以示區別。Quartz.Net可以實現諸如定時發送郵件、定時處理數據、定時輪詢數據庫等計划任務,只需要幾句代碼,不需要Windows計划任務也能實現諸如“每天早上8:00發送郵件”、“每隔半個小時查詢一次庫存”之類的目的。
安裝Quartz.Net
Quartz.Net的安裝可以說非常簡單,使用NuGet管理器是非常方便的。打開Asp.Net項目,我這里用的是WebApi做的例子(當然用MVC、WPF等也是可以的),打開Nuget管理器,查找Quartz.Net,點擊安裝。
安裝完成后會發現項目自動添加了三個類庫的引用,分別是Common.Logging、Common.Logging.Core、Quartz,其中Quartz是我們需要用到的核心類庫,其余兩個是日志相關的類庫。
Quartz.Net使用示例
這里我將采用上篇的定時發送郵件的示例來說明Quartz.Net,目標是每半個小時發送一封郵件。
發送郵件方法
public async Task<int> Auto() { int num = 0; try { MailModel model = new MailModel() { ReceiverAddress = "",//收件人地址 ReceiverName = "",//收件人姓名 Title = "",//郵件標題 Content = "",//郵件內容 SenderAddress = "",//發件人地址 SenderName = "",//發件人姓名 SenderPassword = ""//發件人密碼 }; bool result = MailHelper.SendMail(model); } catch (Exception) { num = -1; } return await Task.FromResult(num); }
創建發送郵件的任務
Quzrtz中有Job的概念,Job就是我們所講的任務。
using Quartz; using Quartz.Impl; public class TimeJob : IJob { public void Execute(IJobExecutionContext context) { //具體的方法 Auto(); } }
創建類TimeJob並繼承Quzrtz中的接口IJob,實現接口IJob中的方法Execute,在Execute方法中可以創建具體的方法。
創建任務調度器
public class JobScheduler { public static void Start() { //調度器工廠 ISchedulerFactory factory = new StdSchedulerFactory(); //調度器 IScheduler scheduler = factory.GetScheduler(); scheduler.GetJobGroupNames(); /*-------------計划任務代碼實現------------------*/ //創建任務 IJobDetail job = JobBuilder.Create<TimeJob>().Build(); //創建觸發器 ITrigger trigger = TriggerBuilder.Create().WithIdentity("TimeTrigger", "TimeGroup").WithSimpleSchedule(t => t.WithIntervalInMinutes(30).RepeatForever()).Build(); //添加任務及觸發器至調度器中 scheduler.ScheduleJob(job, trigger); /*-------------計划任務代碼實現------------------*/ //啟動 scheduler.Start(); } }
創建任務調度器類JobScheduler,把上面的定時發送郵件任務TimeJob和觸發器添加到任務調度器中。任務Job就是具體要做的事情,觸發器Trigger就是任務要執行的時機。可以創建多個Job任務和多個Trigger觸發器加入到調度器中。
啟動計划任務
任務調度器已經完成了,下步要做的就是在程序啟動時開啟任務調度器了。在項目的Global.asax.cs中進行如下配置
public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); //注冊定時任務 Helpers.JobScheduler.Start(); GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } }
使用配置文件實現計划任務
上面就是一個簡單的定時任務示例,但是還有一點不足之處,那就是觸發器的配置是在代碼中寫的,如果我們想由原來的半個小時發一次改成一個小時發一次,就需要改代碼、編譯、發布,顯然太麻煩,有沒有更好的方式呢?幸運的是Quartz.Net可以通過XML配置文件實現定時任務。仍然是上面發郵件的例子,我們使用配置文件來實現。
修改Web.config文件
修改項目配置文件Web.config,在configSections節點下添加子節點,對應的添加Quartz的基本配置。在最后一行的“key=”quartz.plugin.xml.fileNames” value=”~/quartz_jobs.xml” ”,表示Quertz的任務調度計划。
<configSections> <!--Quartz--> <section name="quartz" type="System.Configuration.NameValueSectionHandler"/> </configSections> <!--Quartz配置--> <quartz> <add key="quartz.scheduler.instanceName" value="ExampleDefaultQuartzScheduler"/> <add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz"/> <add key="quartz.threadPool.threadCount" value="10"/> <add key="quartz.threadPool.threadPriority" value="2"/> <add key="quartz.jobStore.misfireThreshold" value="60000"/> <add key="quartz.jobStore.type" value="Quartz.Simpl.RAMJobStore, Quartz"/> <!--******************************Plugin配置*********************************************--> <add key="quartz.plugin.xml.type" value="Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz" /> <add key="quartz.plugin.xml.fileNames" value="~/quartz_jobs.xml"/> </quartz>
添加quzrtz_jobs.xml
對應上面提到的配置文件中文件路徑“key=”quartz.plugin.xml.fileNames” value=”~/quartz_jobs.xml” ”,在項目目錄下添加文件quartz_jobs.xml,項目啟動是會從此文件中讀取任務計划來執行,具體內容如下:
<job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"> <processing-directives> <overwrite-existing-data>true</overwrite-existing-data> </processing-directives> <schedule> <!--開始執行一個調度--> <!--任務,可添加多個--> <job> <!--任務名稱【必填】:同一group中多個job的name名不能相同--> <name>TimeJob</name> <!--任務所屬分組【選填】--> <group>Timer</group> <!--任務描述【選填】--> <description>定時任務</description> <!--任務類型【必填】:實現IJob接口完整命名空間的類名,程序集名--> <job-type>WebAPI.Helpers.TimeJob, WebAPI</job-type> <durable>true</durable> <recover>false</recover> </job> <!--觸發器,可添加多個--> <trigger> <!--simple:簡單觸發器類型,cron:復雜觸發器類型【推薦】--> <cron> <!--觸發器名稱【必填】:同一group中多個trigger的name不能相同--> <name>TimeTrigger</name> <!--觸發器組【選填】--> <group>Timer</group> <!--觸發器描述【選填】--> <description>每隔半小時推送未處理報警信息</description> <!--要調度的任務名稱【必填】:必須和對應job節點中的name相同--> <job-name>TimeJob</job-name> <!--要調度的任務的所屬分組【選填】:必須和對應job節點中的group相同--> <job-group>Timer</job-group> <cron-expression>0 */30 * * * ?</cron-expression> </cron> </trigger> <!--結束一個調度--> </schedule> </job-scheduling-data>
修改調度器類
配置文件修改完成后,再對調度器類進行相應修改,只需要將創建任務、觸發器的代碼去掉即可,如下:
public class JobScheduler { public static void Start() { //調度器工廠 ISchedulerFactory factory = new StdSchedulerFactory(); //調度器 IScheduler scheduler = factory.GetScheduler(); scheduler.GetJobGroupNames(); //啟動 scheduler.Start(); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
Quartz.Net使用進階
上面就是我們使用Quartz實現的簡單定時任務,如果要實現更復雜的任務調度,強烈推薦使用cron復雜任務觸發器。cron復雜任務觸發器支持使用cron表達式自定義任務調度,理解了cron表達式的結構和用法,實現各種定制性的任務調度就不會有太大問題了。cron表達式由“秒分時日月星期年”共7段構成,其中“年”是可選的。Quartz官方文檔提供的cron表達式的相關說明。
cron表達式說明
字段名 | 是否必填 | 取值范圍 | 允許特殊字符 |
---|---|---|---|
秒 | 必填 | 0-59 | ,-*/ |
分 | 必填 | 0-59 | ,-*/ |
時 | 必填 | 0-23 | ,-*/ |
日 | 必填 | 1-31 | ,-*?/LW |
月 | 必填 | 1-12或JAN-DEC | ,-*/ |
星期 | 必填 | 1-7或SUN-SAT | ,-*?/LW |
年 | 非必填 | 空,1970-2099 | ,-*/ |
cron特殊字符說明
特殊字符 | 說明 |
---|---|
* | 表示“每”,比如每小時、每分鍾、每日、每年 |
? | 表示不指定具體的值,只能出現在日、星期中 |
- | 表示范圍,比如時字段中10-12表示10點、11點、12點 |
, | 表示列舉,比如“MON,WED,FRI”表示周一、周三和周五 |
/ | 表示增量,比如在秒字段中“0/15”表示從0秒開始每次增加15秒,也就是15、30、45秒 |
L | 表示最后的,只能出現在日、星期字段中,表示一個月的最后一天、一個星期的最后一天 |
W | 表示工作日,指距離給定日期最近的工作日 |
# | 表示一個月的第幾個星期幾,比如“6#3”表示每個月的第三個周五 |
cron表達式示例
表達式 | 含義 |
---|---|
0 0 12 * * ? | 每天12點 |
0 15 10 ? * * | 每天10:15 |
0 15 10 * * ? | 每天10:15 |
0 15 10 * * ? * | 每天10:15 |
0 15 10 * * ? | 2005年每天10:15 |
0 * 14 * * ? | 每天14:00到14:59期間的每一分鍾 |
0 0/5 14 * * ? | 每天14:00到14:55期間的每5分鍾 |
0 0/5 14,18 * * ? | 每天14:00到14:55和18:00到18:55期間的每5分鍾 |
0 0-5 14 * * ? | 每天14:00到14:05期間的每一分鍾 |
0 10,44 14 ? 3 WED | 每年三月的星期三的14:10和14:44 |
0 15 10 ? * MON-FRI | 周一到周五的10:15 |
0 15 10 15 * ? | 每月15日的10:15 |
0 15 10 L * ? | 每月最后一天的10:15 |
0 15 10 L-2 * ? | 每月倒數第二天的10:15 |
0 15 10 ? * 6L | 每月最后一個周五的10:15 |
0 15 10 ? * 6L 2002-2005 | 從2002年至2005年期間每月最后一個周五的10:15 |
0 15 10 ? * 6#3 | 每月第三個周五的10:15 |
0 0 12 1/5 * ? | 從每月第一天開始,每隔5天的12:00 |
0 11 11 11 11 ? | 每年11月11日11:11 |
Quartz定時任務日志
通過日志記錄定時計划的執行情況是很有用的,Quartz自身提供的Common.Logging來記錄日志,我們也可以結合Log4net或者Nlog來實現定時任務的運行日志,當然也可以保存到數據庫中,具體方法本文不再詳細說明。
以上就是關於Quartz.Net開源計划調度框架的簡單說明,更詳細的內容請參考Quartz的官網