1. 程式人生 > >Quartz.NET筆記整理,例項,動態改變週期排程。misfire、Cron

Quartz.NET筆記整理,例項,動態改變週期排程。misfire、Cron

Quartz:Java編寫的開源的任務排程作業框架 類似Timer之類定時執行的功能,但是更強大

Quartz.NET:是把Quartz轉成C#  NuGet中可以直接下載對應類庫

官網:https://www.quartz-scheduler.net/

主要物件:

  • Job :工作,要執行的具體內容繼承IJob。此介面中只有一個方法:execute(IJobExecutionContext context) 
  • JobDetail:具體的可執行的排程程式,Job 是這個可執行程排程程式所要執行的內容
  • Trigger:排程引數的配置,什麼時候去調 執行間隔。 
  • Scheduler:排程容器,一個排程容器中可以註冊多個 JobDetail 和 Trigger。當 Trigger 與 JobDetail 組合,就可以被 Scheduler 容器排程了。 

大體介紹:

 static void Main(string[] args)
        {
            Task<IScheduler> task_scheduler = StdSchedulerFactory.GetDefaultScheduler();
            IScheduler scheduler = task_scheduler.Result;

            //ISchedulerFactory _SchedulerFactory = new StdSchedulerFactory();
            //IScheduler scheduler = _SchedulerFactory.GetScheduler().Result;

            /*  
             *   過程:
             *      一.通過StdSchedulerFactory計劃工廠物件建立排程計劃Scheduler
             *      二.建立Job物件,需要繼承IJob 實現執行方法
             *      三.觸發物件,2種:間隔執行和定時執行
             *          1.ITrigger:間隔執行
             *          2.ICronTrigger:定時執行
             *      四.將job物件和觸發物件傳入排程計劃Scheduler 開始執行
             *  
             * 
             */
            //job建立
            IJobDetail job = JobBuilder.Create<SayHello>().WithIdentity("定時確認完成訂單").Build();

            ////建立簡單計時器
            //ISimpleTrigger _SimpleTrigger = TriggerBuilder.Create()
            //    .WithSimpleSchedule(t => t //宣告定時
            //    .WithIntervalInSeconds(2) //5秒一次
            //    .RepeatForever()) //永遠執行
            //    .StartNow() //立即開始
            //    .Build() //建立
            //    as ISimpleTrigger;
            ////關聯job與計時器
            //scheduler.ScheduleJob(job, _SimpleTrigger);
            /*
             * WithCronSchedule引數說明:
             *  秒 分 時 某一天 月 周 年(可選引數,一般不用)
             *  秒分的合法值為0-59,小時:0-23,日期(天):0-31[要注意不同的月份中的天數不同] 月:0-11[或JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC] 星期:1-7(1=星期日)或[SUN,MON,TUE,WED,THU,FRI,SAT]    (程式設計師數數法。。 萬事0開始)( 涉及到星期最好用英文)
             *      萬用字元{[, - * /]都可以使用、[L #]只能星期課額外使用、[L W]天數可額外使用}
             *          ',' 子條件
             *          '*' 代表任意值的所有 
             *          '-' 代表一個時段 
             *          '/' 代表值的增量 
             *                  比如:分鐘域中放入'0/15' 表示【從0開始 每隔15分鐘】 '3/20'表示【從第3分鐘開始 每隔20分鐘】 等同【3,23,43】
             *          '?' 只能用在天數或者星期中 表示【沒有指定值,滿足所有】 
             *          'L' 只能用在天數或者星期中 表示【這個時段的最後一天】 
             *                  比如:月份中 1月的31號 2月的28或者29號 反正最後一天,或者 4L:該月的最後一個週四 6L:該月的最後一個週四。  
             *                  注意!星期中表示【週六 SAT(手動加粗)】 
             *          'W' 代表離給定日期最近的那個工作日
             *                  比如:天數設定為15W 表示【離本月15號最近的一個工作日】??
             *          'LW'代表這個月最後一週的工作日 可以在日期使用 ?待測
             *          '#' 代表本月的第幾個工作日
             *                  比如:星期中設定6#3 當月的第三個週五(6是週五!)
             * 
             *  過失觸發:
             *    withMisfireHandlingInstructionDoNothing--->misfireInstruction = 2
             *     ——不觸發立即執行
             *     ——等待下次Cron觸發頻率到達時刻開始按照Cron頻率依次執行
             *
             *    withMisfireHandlingInstructionFireAndProceed--->misfireInstruction = 1
             *     ——以當前時間為觸發頻率立刻觸發一次執行
             *     ——然後按照Cron頻率依次執行
             *
             *     withMisfireHandlingInstructionIgnoreMisfires--->misfireInstruction = -1
             *     ——以錯過的第一個頻率時間立刻開始執行
             *     ——重做錯過的所有頻率週期後
             *     ——當下一次觸發頻率發生時間大於當前時間後,再按照正常的Cron頻率依次執行
             * 
             * 
             * 
             * 例項:
             *      "0 0/5 * * * ?" 每5分鐘
             *      "10 0/5 * * * ?" 這分鐘後 10 秒起, 每五分鐘
             *      "0 30 10-13 ? * WED,FRI" 每週三、週五的10點到13點的30分時 【每週三, 週五 10:30, 11:30, 12:30 和 13:30】
             *      "0 0/30 8-9 5,20 * ?" 每個月的5號、20號的8點9點之間 每半小時觸發一次 因為0開始 所以10點的時候不觸發【8:00, 8:30, 9:00  9:30 】
             *      "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 ? * 6#3" 每個月第三個週五的10:15
             * 
             *   生成表示式的網站:http://cron.qqe2.com/?tdsourcetag=s_pctim_aiomsg 小時模組的增量有bug注意下 但大體不影響使用
            */
            ICronTrigger _CronTrigger = TriggerBuilder.Create()
                .WithIdentity("定時確認")
                .WithCronSchedule("0/2 * * * * ?") //秒 分 時 某一天 月 周 年(可選引數)
                .Build()
                as ICronTrigger;
            scheduler.ScheduleJob(job, _CronTrigger);


            scheduler.Start();
            Console.ReadLine();
        }
    }

    public class SayHello : IJob
    {
        public async Task Execute(IJobExecutionContext context)
        {
            Console.WriteLine("Hello Wrold!");
        }
    }

 

 

例項:

1.建立job

 public class SayHello : IJob
    {
        public static int ii = 0;
        static string str = "服務1=Cron 5秒一次。Hello World==SayHello  ";
        public async Task Execute(IJobExecutionContext context)
        {
             
            if (ii == 1)
            {
                QuartzManage.ModifyJob(context.JobDetail, context.Trigger as ICronTrigger, "0/2 * * * * ?");
                ii = 0;
                str += ",週期已改變!!變成2秒一次 ";
            }
            Common.WriteLog(str + context.Scheduler.GetHashCode());
        }
    }

    public class SayCZ : IJob
    {
        public async Task Execute(IJobExecutionContext context)
        {
            Common.WriteLog("服務2=Simple 3秒一次。Hello CZ==SayCZ  " + context.Scheduler.GetHashCode());
        }
    }

2.Quartz管理類

public class QuartzManage
    {
        static Task<IScheduler> task_scheduler = StdSchedulerFactory.GetDefaultScheduler();
        static IScheduler scheduler;
        private static readonly object objlock = new object();
        static QuartzManage()
        {
            if (scheduler == null)
            {
                lock (objlock)
                {
                    if (scheduler == null)
                        scheduler = task_scheduler.Result;
                }
            }
        }

        /// <summary>
        /// 以Simple開始一個工作
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <param name="simpleInterval"></param>
        public static void StartJobWithSimple<T>(string name, Action<SimpleScheduleBuilder> simpleInterval) where T : IJob
        {
            IJobDetail job = JobBuilder.Create<T>().WithIdentity(name + "_job", name + "_group").Build();
            ITrigger Simple = TriggerBuilder.Create().StartNow()
                               .WithSimpleSchedule(simpleInterval)
                               .Build() as ISimpleTrigger;

            scheduler.ScheduleJob(job, Simple);
            scheduler.Start();
        }

        /// <summary>
        /// 以Cron開始一個工作
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <param name="CronExpression"></param>
        public static void StartJobWithCron<T>(string name, string CronExpression) where T : IJob
        {

            IJobDetail job = JobBuilder.Create<T>().WithIdentity(name + "_job", name + "_group").Build();

            ITrigger CronTrigger = TriggerBuilder.Create().StartNow().WithIdentity(name + "_trigger", name + "_group")
                                    .WithCronSchedule(CronExpression, w => w.WithMisfireHandlingInstructionDoNothing())
                                    .Build() as ICronTrigger;

            scheduler.ScheduleJob(job, CronTrigger);
            scheduler.Start();
        }

        /// <summary>
        /// Cron修改頻率
        /// </summary>
        /// <param name="job"></param>
        /// <param name="trigger"></param>
        /// <param name="CronExpression"></param>
        public static void ModifyJob(IJobDetail job, ICronTrigger trigger, string CronExpression)
        {
            ICronTrigger _ICronTrigger = trigger;
            _ICronTrigger.CronExpressionString = CronExpression;

            scheduler.RescheduleJob(trigger.Key, _ICronTrigger);
        }

        /// <summary>
        /// Simple修改頻率
        /// </summary>
        /// <param name="job"></param>
        /// <param name="trigger"></param>
        /// <param name="SimpleTime"></param>
        public static void ModifyJob(IJobDetail job, ISimpleTrigger trigger, TimeSpan SimpleTime)
        {
            ISimpleTrigger _ISimpleTrigger = trigger;
            _ISimpleTrigger.RepeatInterval = SimpleTime;

            scheduler.RescheduleJob(trigger.Key, _ISimpleTrigger);
        }

    }

3.執行排程,並改變週期

 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        /// <summary>
        /// Cron
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            QuartzManage.StartJobWithCron<SayHello>("first", "0/5 * * * * ?");
        }

        /// <summary>
        /// Simple執行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            QuartzManage.StartJobWithSimple<SayCZ>("second", x => x.WithIntervalInSeconds(3).RepeatForever()); //每三秒 一直執行
        }

        private void button3_Click(object sender, EventArgs e)
        {
            SayHello.ii = 1;
        }
    }

執行結果:

改變週期後 會有一個過時觸發的問題 根據設定不同的模式 執行的效果不同 misfire的概念,第一個程式碼塊中有詳細註釋說明

 

程式碼例項: https://download.csdn.net/download/commandbaby/10664266