關於Quartz .NET(V3.0.7)的簡要說明

shanzm-2020年3月25日 21:28:09

0. 任務調度

好比說,財務系統須要在每月初生成上一個月的財務報表。html

好比說,天天或每週固定時間對數據庫更新。git

好比說,天天定時發送郵件。github

這些須要在某個預約的時間點週期性的執行某個特定的任務的功能(也就是任務調度),可使用任務調度框架——Quartz .NET數據庫

Quartz.NET是一個開源的任務調度框架(做業調度框架),是從Java移植過來的,使用較爲普遍!express



1. Quartz .NET

1.1 基本概念

調度器(Scheduler):存放觸發器和定時任務,根據觸發器執行定時任務框架

觸發器(Trigger):決定執行時間,執行間隔,運行次數,故觸發器用來告訴調度程序做業何時觸發異步

任務(Job):須要定時或是週期性執行的任務async

使用流程:ui

建立調度器-->建立任務-->建立觸發器-->Job和Trigger註冊到調度器-->啓動調度器;.net

1.2 主要接口和對象

接口/類 做用
IScheduler 調度器接口
IJob 任務接口,將須要定時執行的方法實如今該接口的Excute方法中
IJobDetail 用於定義Job的實例
ITrigger 觸發器接口
JobBuilder 任務構造者:用於建立任務實例
TriggerBuilder 觸發器構造者:用於建立觸發器實例
JobDetailImpl 實現了IJobDetail類
JobKey 任務名
TriggerKey 觸發器名

其中觸發器的類型

觸發器最經常使用的主要有兩種:

SimpleTrigger:用於指定任務重複執行的時間間隔

IMutableTrigger:用於指定任務重複執行的具體時間



2. 使用示例

2.0 準備工做

①安裝Quartz程序包

當前時間:2020年3月18日 23:20:59,最新版本的Quartz.NET爲3.0.7

每次的版本的變化,API變化都好大,因此在這裏註明當前的使用版本!

建議使用最新版本,新版本都是異步方法實現的。

NuGet:Install-Package Quartz -Version 3.0.7

②新建TestJob.cs
實現IJob接口

public class TestJob : IJob
{
    public async Task Execute(IJobExecutionContext context)
    {
        await Task.Run(() => Console.WriteLine($"{DateTime.Now}:執行任務了……"));
    }
}

2.1 每間隔必定時間間隔執行一次任務

//間隔5s重複一次執行指定的任務
public static async void WithInterval()
{
    //-------1.準備調度者
    ISchedulerFactory factory = new StdSchedulerFactory(); //建立調度器工廠
    IScheduler scheduler = await factory.GetScheduler(); //建立調度者

    //-------2.準備任務
    JobBuilder jobBuilder = JobBuilder.Create<TestJob>();//建立任務構造者:JobBuilder
    IJobDetail job1 = jobBuilder.Build();//建立任務

    //-------3.準備觸發器
    TriggerBuilder triggerBuilder = TriggerBuilder.Create()
    .StartNow()//當即生效
    .WithSimpleSchedule(x=>x.WithIntervalInSeconds(5)
    .RepeatForever());  //建立觸發器構造者:TriggerBuilder
    ISimpleTrigger trigger = triggerBuilder.WithIdentity("trigger1","group2").Build() as ISimpleTrigger;//建立觸發器

    //-------4.將任務與觸發器添加到調度器中
    await scheduler.ScheduleJob(job1, trigger);
    await scheduler.Start();//開始執行
}

【代碼說明】

  • 示例中使用的而是ISimpleTrigger類型的觸發器,能夠精準的設置任務重複的時間間隔。

  • 其中的觸發器構造者中的

    triggerBuilder.StartNow()表示觸發器當即生效

    triggerBuilder.StartAt(DateTimeOffset startTimeUtc)設置觸發器生效的時間

    triggerBuilder.EndAt(DateTimeOffset startTimeUtc)設置觸發器失效的時間

  • 其中使用WithIntervalInSeconds(5)表示每五秒觸發一次任務

    其餘的一些按照小時和天的作間隔,以及明確觸發次數的方法都簡單明確,根據VS的智能提示便可瞭解,不一一列舉於此!

  • 示例中使用RepeatForever()表示重複無窮次,仍是可使用WithRepeatCount()設置重複的次數的。

    這裏有一個細節問題,好比說,設置執行三次,WithRepeatCount(3),可是注意實際會執行4次


2.3 某天的固定時間點執行任務

Quartz.NET的接口比較繁多,第一個示例中是使用的最基礎的方法,下面代碼示例將換一種簡寫的方式。

//天天按照指定的時間點執行任務
public static async void AtHourAndMinute()
{
    //建立調度器
    IScheduler scheduler = await new StdSchedulerFactory().GetScheduler();
    //建立任務
    //JobDetailImpl job1 = new JobDetailImpl("TestJob1", "group1", typeo(TestJob))//JobDetailImpl是IJobDetail的實現類
    //等價於:
    IJobDetail job1 = JobBuilder.Create<TestJob>().WithIdentity("Testjob1""group1").Build();
    //建立觸發器
    IMutableTrigger trigger2job1 = CronScheduleBuilder.DailyAtHourAndMinut(03, 50).Build();//天天更具某時間點重複觸發任務
    //將任務和觸發器添加到調度器中
    trigger2job1.Key = new TriggerKey("trigger1");//注意必定要給觸發器命名
    await scheduler.ScheduleJob(job1, trigger2job1);
    //開始執行調度者
    await scheduler.Start();
}

【代碼說明】

  • 示例中使用的是IMutableTrigger類型的觸發器

  • 經過CronScheduleBuilder類的靜態方法能夠設置觸發的具體的某一日

    設置觸發時間爲天天的某時某分DailyAtHourAndMinut(03, 50)

    設置觸發時間是一週中的哪幾天中的幾時幾分AtHourAndMinuteOnGivenDaysOfWeek(int hour , int min, params DayOfWeek[] daysOfWeek)

    設置觸發時間是每個月中某天某時某分CronScheduleBuilder.MonthlyOnDayAndHourAndMinute(int dayOfMonth, int hour, int min).Build()

  • 封裝好的一些方法仍是有必定侷限的(可是我本身夠用的了),關於其餘的一些複雜的週期任務,都是可使用cron expression,使用cron expression能夠定義你能想到的全部觸發時間和週期

    cron expression什麼樣?怎麼用?例如設置觸發的時間是:每一年每個月的2點18分40秒CronScheduleBuilder.CronSchedule("40 18 2 ? * * *").WithIdentity("trigger1").Build();

    關於cron expression寫起來仍是有點麻煩的,可使用一些在線生成器爲咱們自動的生成指望的表達式。

    推薦:Cron Expression Generator


2.4 封裝整個定時任務,並給任務傳遞參數

前面的示例爲了簡潔的表示Quartz.NET的一些API的使用,

項目中都是把爲定時任務,整個的操做流程封裝在一個靜態方法中,存放在咱們自定義的Job類中

作一個簡單的示例:定時發送短信。

自定義Job,實現IJob接口,同時把建立調度器對象,建立觸發器和任務封裝於其中,做爲一個靜態方法

class TestJob2 : IJob
{
    public async Task Execute(IJobExecutionContext context)
    {
        try
            {
                JobDataMap dataMap = context.MergedJobDataMap;
                string tag = dataMap.GetString("tag");
                string title = dataMap.GetString("title");
                string content = dataMap.GetString("content");
                string description = dataMap.GetString("description");
                string tels = dataMap.GetString("tels");

                //執行定時任務:模擬發送短信
                await Task.Run(() => Console.WriteLine($"發短信:【{tag}】,{title}:{content },{description},電話:{tels}。"));

                //await context.Scheduler.Shutdown();//表示完成當前的定時任務,關閉調度器

                //記入日誌
                Console.WriteLine("執行了一次定時任務,記入日誌");
            }
            catch (Exception ex)
            {
                //記入日誌Log.Error()
                Console.WriteLine(ex.Message);
            }
    }

    //將建立定時任務的全部操做封裝在此
    public static async void SendMessage(string starttime, string cronStr,string tag, string title, string content,string description, string tels)
    {
        try
        {
            //建立調度器
            IScheduler scheduler = await new StdSchedulerFactory().GetScheduler();
            //爲任務準備參數
            DateTime time = DateTime.Parse(starttime);
            JobDataMap jobData = new JobDataMap()
            {
                new KeyValuePair<string, object>("tag", tag),
                new KeyValuePair<string, object>("title", title),
                new KeyValuePair<string, object>("content", content),
                new KeyValuePair<string, object>("description", description),
                new KeyValuePair<string, object>("tels", tels),
            };
            //建立任務:
            //注意能夠用時間作組名:DateTime.Now.ToLongDateString()
            IJobDetail job = JobBuilder.Create<TestJob2>()
                                       .WithIdentity("Testjob1", "group1")
                                       .SetJobData(jobData)
                                       .Build();
            //建立觸發器
            ITrigger trigger = TriggerBuilder.Create()
                                             .WithIdentity("triger1", "group1")
                                             .StartAt(time)//觸發器開始時間//.StartNow()如今開始
                                             .WithCronSchedule(cronstr)
                                             .Build();
            //將任務和觸發器添加到調度器中
            await scheduler.ScheduleJob(job, trigger);
            await scheduler.Start();
        }
        catch (Exception ex)
        {
            //記入日誌
            Console.WriteLine(ex.Message);
        }
    }
}

調用:

public static async void PackageJob()
{
    //從系統當前時間,每隔5s,發送一條短信:【新聞】,新冠病毒,治癒者愈來愈多,普天同慶,10086。
    await Task.Run(() => TestJob2.SendMessage(DateTime.Now .ToString(),"/5 * * ? * *","新聞", "新冠病毒", "治癒者愈來愈多", "普天同慶", "10086"));
}

【代碼說明】

  • 使用JobDataMap類型存放須要傳遞到IJob接口的Excute(IJobExecutionContext context)方法中

    JobDataMap中以鍵值對的方式存放數據,jobDataMao.Add("key",value)

  • 在定義Job的時候,使用觸發器對象中的方法jobBuilder.SetJobData(jobData)將JobDataMap類型的數據傳遞到任務中

  • 使用JobDataMap dataMap = context.MergedJobDataMap;獲取傳遞到Excute()中的JobDataMap類型的數據

    使用string value = dataMap.GetString("key");獲取數據

  • 由於定時任務的是延時的執行的,因此切記必定要把每一個週期中執行的定時任務記入到日誌中,便於維護管理!

  • 注意,由於實現了IJob接口的任務類,其Excute()方法是在一個單獨的線程中運行的,因此其異常的處理也在Excute()中使用try……catch……進行處理

  • BTW:在MVC項目中使用Quartz .NET,直接在Global.asax.cs中的Application_Start()運行封裝好的定時任務便可

    注意:使用Quartz.NET中的Job,是沒法實現任何關於Web的相關操做


2.5 關於調度器的一些說明

  • 一個調度器中能夠調度多個方法

    使用 scheduler.ScheduleJob(job,trigger)將指定的任務和觸發器添加到指定的調度器中,能夠屢次添加,從而實現一個調度器中調度多個任務

    可是有一點要注意:一個任務能夠有多個觸發器,可是一個觸發器只能對應一個任務

  • 調度器能夠添加任務,那麼就必定是能夠移除任務的

    //中止觸發器
    await scheduler.PauseTrigger(triggerKey);
    //移除觸發器
    await scheduler.UnscheduleJob(triggerKey);
    //刪除任務
    await scheduler.DeleteJob(jobkey);
  • 調度器能夠開始運行,那麼就必定中止運行:

    context.Scheduler.Shutdown();表示完成當前的定時任務,關閉調度器

2.6 關於監聽器

Undone……

可參考監聽器:JobListeners/TriggerListeners/SchedulerListeners



參考及示例代碼下載

相關文章
相關標籤/搜索