天天看點

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

目錄

  • 0. 任務排程
  • 1. Quartz .NET
    • 1.1 基本概念
    • 1.2 主要接口和對象
  • 2. 使用示例
    • 2.0 準備工作
    • 2.1 每間隔一定時間間隔執行一次任務
    • 2.3 某天的固定時間點執行任務
    • 2.4 封裝整個定時任務,并給任務傳遞參數
    • 2.5 關于排程器的一些說明
    • 2.6 關于監聽器
  • 參考及示例代碼下載下傳

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

比如說,财務系統需要在每個月初生成上一個月的财務報表。

比如說,每天或每周固定時間對資料庫更新。

比如說,每天定時發送郵件。

這些需要在某個預定的時間點周期性的執行某個特定的任務的功能(也就是任務排程),可以使用任務排程架構——Quartz .NET

Quartz.NET是一個開源的任務排程架構(作業排程架構),是從Java移植過來的,使用較為廣泛!

排程器(Scheduler):存放觸發器和定時任務,根據觸發器執行定時任務

觸發器(Trigger):決定執行時間,執行間隔,運作次數,故觸發器用來告訴排程程式作業什麼時候觸發

任務(Job):需要定時或是周期性執行的任務

使用流程:

建立排程器-->建立任務-->建立觸發器-->Job和Trigger注冊到排程器-->啟動排程器;

接口/類 作用
IScheduler 排程器接口
IJob 任務接口,将需要定時執行的方法實作在該接口的Excute方法中
IJobDetail 用于定義Job的執行個體
ITrigger 觸發器接口
JobBuilder 任務構造者:用于建立任務執行個體
TriggerBuilder 觸發器構造者:用于建立觸發器執行個體
JobDetailImpl 實作了IJobDetail類
JobKey 任務名
TriggerKey 觸發器名

其中觸發器的類型

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

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

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

①安裝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}:執行任務了……"));
    }
}
           

//間隔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次

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

前面的示例為了簡潔的表示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的相關操作

  • 一個排程器中可以排程多個方法

    scheduler.ScheduleJob(job,trigger)

    将指定的任務和觸發器添加到指定的排程器中,可以多次添加,進而實作一個排程器中排程多個任務

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

  • 排程器可以添加任務,那麼就一定是可以移除任務的
    //停止觸發器
    await scheduler.PauseTrigger(triggerKey);
    //移除觸發器
    await scheduler.UnscheduleJob(triggerKey);
    //删除任務
    await scheduler.DeleteJob(jobkey);
               
  • 排程器可以開始運作,那麼就一定停止運作:

    context.Scheduler.Shutdown();

    表示完成目前的定時任務,關閉排程器

Undone……

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

  • 示例中的源代碼下載下傳
  • 官方文檔:官方教程:Quartz.NET 3.x Tutorial
  • 監聽器:Quartz.NET使用教程
  • Quartz(Java)源碼:Quartz 源碼解析
  • 遠端管理及可視化操作: ASP.NET MVC5 實作基于Quartz.NET任務排程
  • 配置方式1:Quartz.NET文檔 入門教程
  • 配置方式2:Quartz.Net定時任務簡單實用(執行個體)
  • Cron Expression:Cron Expression Generator
  • 封裝任務和傳參:NET作業排程(定時任務)-Quartz.Net
  • 取消任務:Net作業排程-----Quartz.Net

作者:shanzm

[email protected]

歡迎交流,歡迎指教!

繼續閱讀