Quartz.net開源作業調度框架使用詳解


前言

quartz.net作業調度框架是偉大組織OpenSymphony開發的quartz scheduler項目的.net延伸移植版本。支持 cron-like表達式,集群,數據庫。功能性能強大更不用說。

下載項目文檔官網:http://www.quartz-scheduler.net/

項目中需引用:Common.Logging.dll , Common.Logging.Core.dll , Quartz.dll 

下面給大家分解下我最近做的關於計划調度的一個小項目,來輔助理解quartz.net的功能和常用方法。

 

quartz.net的簡單用法 -入門

如果你是quartz.net的使用新手,控制台入門這里,建議跟着做下,那么10分鍾搞懂quartz.net也是 so easy 的事.

1.創建一個每隔3秒鍾執行一次的計划調度

public class RunMain
    {
        static void Main(string[] args)
        {
            Console.WriteLine(DateTime.Now.ToString("r"));
            //1.首先創建一個作業調度池
            ISchedulerFactory schedf = new StdSchedulerFactory();
            IScheduler sched = schedf.GetScheduler();
            //2.創建出來一個具體的作業
            IJobDetail job = JobBuilder.Create<JobDemo>().Build();           
            //3.創建並配置一個觸發器
            ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithSimpleSchedule(x=>x.WithIntervalInSeconds(3).WithRepeatCount(int.MaxValue)).Build();
            //4.加入作業調度池中
            sched.ScheduleJob(job, trigger);
            //5.開始運行
            sched.Start();
            Console.ReadKey();
        }
    }
    public class JobDemo : IJob
    {
        /// <summary>
        /// 這里是作業調度每次定時執行方法
        /// </summary>
        /// <param name="context"></param>
        public void Execute(IJobExecutionContext context)
        {
            Console.WriteLine(DateTime.Now.ToString("r"));
        }
    }

Note:1、記下作業調度創建的順序。2、上述代碼執行結果是,每三秒執行一次JobDemo中的Execute,如果程序不停止,無休無止執行到天荒地老,呵呵,扯下蛋啊。

2.改進(豐富調度計划):上一個作業,我想讓他每三秒執行一次,一共執行100次,開始執行時間設定在當前時間,結束時間我設定在2小時后,不過100次執行完沒2小時候都不再執行。

    public class RunMain
    {
        static void Main(string[] args)
        {
            Console.WriteLine(DateTime.Now.ToString("r"));
            //首先創建一個作業調度池
            ISchedulerFactory schedf = new StdSchedulerFactory();
            IScheduler sched = schedf.GetScheduler();
            //創建出來一個具體的作業
            IJobDetail job = JobBuilder.Create<JobDemo>().Build();
            //NextGivenSecondDate:如果第一個參數為null則表名當前時間往后推遲2秒的時間點。
            DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddSeconds(1), 2);
            DateTimeOffset endTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddHours(2), 3);
            //創建並配置一個觸發器
            ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().StartAt(startTime).EndAt(endTime)                
                                        .WithSimpleSchedule(x=>x.WithIntervalInSeconds(3).WithRepeatCount(100))
                                        .Build();
            //加入作業調度池中
            sched.ScheduleJob(job, trigger);
            //開始運行
            sched.Start();
            Console.ReadKey();
        }
    }
    public class JobDemo : IJob
    {
        /// <summary>
        /// 這里是作業調度每次定時執行方法
        /// </summary>
        /// <param name="context"></param>
        public void Execute(IJobExecutionContext context)
        {
            Console.WriteLine(DateTime.Now.ToString("r"));
        }
    }
View Code

3.繼續改進(cron-like使用):前兩個作業調度都太簡單,如果我想在每小時的第10,20,25,26,33,54分鍾,每分鍾的第1,10,14秒執行一次。那么上面顯然是不能滿足的。這是我就把cron-like表達式引入進來,以實現各種時間緯度的調用。

 public class RunMain
    {
        static void Main(string[] args)
        {
            Console.WriteLine(DateTime.Now.ToString("r"));
            //首先創建一個作業調度池
            ISchedulerFactory schedf = new StdSchedulerFactory();
            IScheduler sched = schedf.GetScheduler();
            //創建出來一個具體的作業
            IJobDetail job = JobBuilder.Create<JobDemo>().Build();
            //NextGivenSecondDate:如果第一個參數為null則表名當前時間往后推遲2秒的時間點。
            DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddSeconds(1), 2);
            DateTimeOffset endTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddYears(2), 3);
            //創建並配置一個觸發器
            ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create().StartAt(startTime).EndAt(endTime)
                                        .WithCronSchedule("1,10,14 10,20,25,26,33,54 * * * ? ")
                                        .Build();
            //加入作業調度池中
            sched.ScheduleJob(job, trigger);
            //開始運行
            sched.Start();
            //掛起2天
            Thread.Sleep(TimeSpan.FromDays(2));
            //2天后關閉作業調度,將不在執行
            sched.Shutdown();
            Console.ReadKey();
        }
    }
    public class JobDemo : IJob
    {
        /// <summary>
        /// 這里是作業調度每次定時執行方法
        /// </summary>
        /// <param name="context"></param>
        public void Execute(IJobExecutionContext context)
        {
            Console.WriteLine(DateTime.Now.ToString("r"));
        }
    }

基於Quartz.net的作業調度項目詳解

最終效果如開篇的第一個圖所示。

下面主要說說,作業調度的中怎么定位到具體的作業調度,並給作業調度分組,命名,添加,啟動,停止。

首先展示下表結構,項目中我叫作業調度為任務調度。

1、新增作業調度。

 /// <summary>
        /// 任務計划
        /// </summary>
        public static IScheduler scheduler = null;
        public static IScheduler GetScheduler()
        {
            if (scheduler != null)
            {
                return scheduler;
            }
            else
            {
                ISchedulerFactory schedf = new StdSchedulerFactory();
                IScheduler sched = schedf.GetScheduler();
                return sched;
            }
        }
 /// <summary>
        /// 添加任務計划
        /// </summary>
        /// <returns></returns>
        public bool AddScheduleJob(WJ_ScheduleEntity m)
        {
            try
            {
                if (m != null)
                {
                    if (m.StarRunTime == null)
                    {
                        m.StarRunTime = DateTime.Now;
                    }
                    DateTimeOffset starRunTime = DateBuilder.NextGivenSecondDate(m.StarRunTime, 1);
                    if (m.EndRunTime == null)
                    {
                        m.EndRunTime = DateTime.MaxValue.AddDays(-1);
                    }
                    DateTimeOffset endRunTime = DateBuilder.NextGivenSecondDate(m.EndRunTime, 1);
                    scheduler = GetScheduler();
                    IJobDetail job = JobBuilder.Create<HttpJob>()
                      .WithIdentity(m.JobName, m.JobGroup)
                      .Build();
                    ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create()
                                                 .StartAt(starRunTime)
                                                 .EndAt(endRunTime)
                                                 .WithIdentity(m.JobName, m.JobGroup)
                                                 .WithCronSchedule(m.CronStr)
                                                 .Build();
                    scheduler.ScheduleJob(job, trigger);
                    scheduler.Start();
                    StopScheduleJob(m.JobGroup, m.JobName);
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                //DoApplication.WriteLogFile(ex.Message + "\r\n" + ex.StackTrace);
                return false;
            }
        }

Note:1.這里作業調度執行的函數如下。2.上面的WithIdentity(m.JobName, m.JobGroup) ,是給作業調度加入組,和名稱,方便我們針對哪一個作業計划,進行啟動停止等操作。

 

 public class HttpJob : IJob
    {
        public void Execute(IJobExecutionContext context)
        {
            ThreadPool.QueueUserWorkItem(delegate(Object o)
            {
                try
                {
                    //DoApplication.WriteLogFile(context.JobDetail.Key.Group + "---" + context.JobDetail.Key.Name + "---" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "---" + context.NextFireTimeUtc.Value.DateTime.AddHours(8).ToString("yyyy-MM-dd HH:mm:ss"));
                    var sm = new WJ_ScheduleManage().GetScheduleModel(new WJ_ScheduleEntity() { JobGroup = context.JobDetail.Key.Group, JobName = context.JobDetail.Key.Name });
                    new WJ_ScheduleManage().UpdateScheduleRunStatus(new WJ_ScheduleEntity() { JobGroup = context.JobDetail.Key.Group, JobName = context.JobDetail.Key.Name,RunStatus=(int)ADJ.Job.Entity.EnumType.JobRunStatus.執行中 });
                    ESBRequest req = new ESBRequest(sm.ServiceCode, sm.ApiCode);
                    DataResult result = req.Request();
                    new WJ_ScheduleManage().UpdateScheduleRunStatus(new WJ_ScheduleEntity() { JobGroup = context.JobDetail.Key.Group, JobName = context.JobDetail.Key.Name, RunStatus = (int)ADJ.Job.Entity.EnumType.JobRunStatus.待運行 });
                    if (result.Code == 1)
                    {
                        #region 加入執行明細
                        WJ_ScheduleDetailsEntity dm = new WJ_ScheduleDetailsEntity();
                        dm.ActionDescribe = "執行完成:" + result.Message ;
                        dm.ActionStep = (int)ADJ.Job.Entity.EnumType.JobStep.執行完成;
                        dm.CreateTime = DateTime.Now;
                        dm.JobGroup = context.JobDetail.Key.Group;
                        dm.JobName = context.JobDetail.Key.Name;
                        dm.IsSuccess = 1;
                        new WJ_ScheduleManage().AddScheduleDetails(dm);
                        #endregion
                    }
                    else
                    {
                        #region 加入執行明細
                        WJ_ScheduleDetailsEntity dm = new WJ_ScheduleDetailsEntity();
                        dm.ActionDescribe = "執行任務計划中,執行計划過程出錯."+result.Message;
                        dm.ActionStep = (int)ADJ.Job.Entity.EnumType.JobStep.執行任務計划中;
                        dm.CreateTime = DateTime.Now;
                        dm.JobGroup = context.JobDetail.Key.Group;
                        dm.JobName = context.JobDetail.Key.Name;
                        dm.IsSuccess = 0;
                        new WJ_ScheduleManage().AddScheduleDetails(dm);
                        #endregion
                    }
                    new WJ_ScheduleManage().UpdateScheduleNextTime(new WJ_ScheduleEntity() { JobGroup = context.JobDetail.Key.Group, JobName = context.JobDetail.Key.Name, NextTime = context.NextFireTimeUtc.Value.DateTime.AddHours(8) });
                }
                catch (Exception ex)
                {
                    #region 加入執行明細
                    WJ_ScheduleDetailsEntity dm = new WJ_ScheduleDetailsEntity();
                    dm.ActionDescribe = "執行任務計划中,執行計划過程出錯:" + ex.Message + "/r/n" + ex.StackTrace;
                    dm.ActionStep = (int)ADJ.Job.Entity.EnumType.JobStep.執行任務計划中;
                    dm.CreateTime = DateTime.Now;
                    dm.JobGroup = context.JobDetail.Key.Group;
                    dm.JobName = context.JobDetail.Key.Name;
                    dm.IsSuccess = 0;
                    new WJ_ScheduleManage().AddScheduleDetails(dm);
                    #endregion
                    DoApplication.WriteLogFile(ex.Message + "\r\n" + ex.StackTrace);
                }
            });
        }
    }
View Code

note:這里執行的Execute方法參數IJobExecutionContext 中,會自動把作業調度的詳細信息帶過來,作業名稱,作業組名,作業下次執行時間,作業執行時間等等,這里的內容也是至關重要的,比如根據作業組,作業名稱我們可以從數據庫找到相應的作業調度詳細,更新操作數據庫

2、針對某個作業計划進行停止,啟動。

 /// <summary>
        /// 暫停指定任務計划
        /// </summary>
        /// <returns></returns>
        public JsonResult StopScheduleJob(string jobGroup, string jobName)
        {
            try
            {
                scheduler = GetScheduler();                
                scheduler.PauseJob(new JobKey(jobName, jobGroup));
                new WJ_ScheduleManage().UpdateScheduleStatus(new WJ_ScheduleEntity() { JobName = jobName, JobGroup = jobGroup, Status = (int)ADJ.Job.Entity.EnumType.JobStatus.已停止 });               
                return Json(new StatusView() { Status = 0, Msg = "停止任務計划成功!" }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {               
                DoApplication.WriteLogFile(ex.Message + "/r/n" + ex.StackTrace);
                return Json(new StatusView() { Status = -1, Msg = "停止任務將計划失敗!" }, JsonRequestBehavior.AllowGet);
            }
        }
        /// <summary>
        /// 開啟指定的任務計划
        /// </summary>
        /// <returns></returns>
        public JsonResult RunScheduleJob(string jobGroup, string jobName)
        {
            try
            {
                var sm = new WJ_ScheduleManage().GetScheduleModel(new WJ_ScheduleEntity() { JobName = jobName, JobGroup = jobGroup });
                AddScheduleJob(sm);
                sm.Status = (int)ADJ.Job.Entity.EnumType.JobStatus.已啟用;
                new WJ_ScheduleManage().UpdateScheduleStatus(sm);
                scheduler = GetScheduler();
                scheduler.ResumeJob(new JobKey(jobName, jobGroup));
                return Json(new StatusView() { Status = 0, Msg = "啟動成功!" }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
              
                DoApplication.WriteLogFile(ex.Message + "/r/n" + ex.StackTrace);
                return Json(new StatusView() { Status = -1, Msg = "啟動失敗!" }, JsonRequestBehavior.AllowGet);
            }
        }

最后注意:

1、這個項目完全使用啦cron-like表達式實現觸發器配置,如果你對cron不了解,那么我上篇中有針對cron做介紹講解,如果你對cron了解而沒有一個合適的生成工具,那么入左上方2個群,找我。

2、這個項目部署在IIS中,那么就要設置應用程序池的回收機制為,永不回收,配置下,如果不會配置,入左上方2個群,找我。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM