天天看點

Quartz.NET開源作業排程架構系列(三):IJobExecutionContext 參數傳遞

  前面寫了關于Quartz.NET開源作業排程架構的入門和Cron Trigger , 這次繼續這個系列, 這次想讨論一下Quartz.NET中的Job如何通過執行上下文(Execution Contex)進行參數傳遞 , 有些參數想儲存狀态該如何處理 。 在Quartz.NET中可以用JobDataMap進行參數傳遞。本例用Quartz.NET的任務來定期輪詢資料庫表,當資料庫的條目達到一定的數目後,進行預警。(其實可以将讀取的表和預警條件配置到資料庫中的預警條件表中,這樣就可以簡單實作一個自動預警提醒的小平台)。

1 JobWithParametersExample

using System;
using System.Threading;
using Common.Logging;
using Quartz;
using Quartz.Impl;
using Quartz.Job;
using Quartz.Impl.Calendar;
using Quartz.Impl.Matchers;
namespace QuartzDemo
{

    public class JobWithParametersExample
    {
        public string Name
        {
            get { return GetType().Name; }
        }
        private IScheduler sched = null;
        public JobWithParametersExample(IScheduler _sched)
        {
            sched = _sched;
        }
        public virtual void Run()
        {

            //2S後執行
            DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(null, 2);
            IJobDetail job1 = JobBuilder.Create<JobWithParameters>()
                .WithIdentity("job1", "group1")
                .Build();

            ISimpleTrigger trigger1 = (ISimpleTrigger)TriggerBuilder.Create()
                       .WithIdentity("trigger1", "group1")
                       .StartAt(startTime)
                       .WithSimpleSchedule(x => x.WithIntervalInSeconds(5).WithRepeatCount(100))
                       .Build();

            // 設定初始參數
            job1.JobDataMap.Put(JobWithParameters.tSQL, "SELECT * FROM [ACT_ID_USER]");
            job1.JobDataMap.Put(JobWithParameters.ExecutionCount, 1);

            // 設定監聽器
            JobListener listener = new JobListener();
            IMatcher<JobKey> matcher = KeyMatcher<JobKey>.KeyEquals(job1.Key);
            sched.ListenerManager.AddJobListener(listener, matcher);

            // 綁定trigger和job
            sched.ScheduleJob(job1, trigger1);
            //啟動
            sched.Start();

        }
    }
}      

  JobWithParametersExample用來配置job和trigger,同時定義了一個監聽器,來監聽定義的job.

2 JobWithParameters

using System;
using Common.Logging;
using Quartz;
using Quartz.Impl;
using Quartz.Job;
using System.Windows.Forms;
namespace QuartzDemo
{

    [PersistJobDataAfterExecution]
    [DisallowConcurrentExecution]
    public class JobWithParameters : IJob
    {

        // 定義參數常量
        public const string tSQL = "tSQL";
        public const string ExecutionCount = "count";
        public const string RowCount = "rowCount";
        public const string tableAlert = "tAlert";
        //  Quartz 每次執行時都會重新執行個體化一個類, 是以Job類中的非靜态變量不能存儲狀态資訊
         private int counter = 1;//都為1
        //private static  int counter = 1;//可以儲存狀态
        public virtual void Execute(IJobExecutionContext context)
        {

            JobKey jobKey = context.JobDetail.Key;
            // 擷取傳遞過來的參數
            JobDataMap data = context.JobDetail.JobDataMap;
            string SQL = data.GetString(tSQL);
            int count = data.GetInt(ExecutionCount);

            if (isOpen("FrmConsole"))
            {
                try
                {
                    //擷取目前Form1執行個體
                    __instance = (FrmConsole)Application.OpenForms["FrmConsole"];
                    //擷取目前執行的線程ID
                    __instance.SetInfo(jobKey + "Thread ID " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
                    //資料庫操作
                    System.Data.DataTable tAlert = SqlHelper.getDateTable(SQL, null);
                    //回寫條數
                    data.Put(RowCount, tAlert.Rows.Count);
                    //通過方法更新消息
                    __instance.SetInfo(string.Format("{0} exec {1} = {2} get {3} rows\r\n           execution count (from job map) is {4}\r\n           execution count (from job member variable) is {5}",
                    jobKey,
                    tSQL,
                    SQL,
                    tAlert.Rows.Count,
                    count, counter));
                    //怎麼取出Datatable ? json to datatable
                    //data.Put(tableAlert, tAlert);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
            // 修改執行計數并回寫到job data map中
            count++;
            data.Put(ExecutionCount, count);
            // 修改本地變量,如果是非靜态變量,不能存儲狀态
            counter++;
        }

        private static FrmConsole __instance = null;

        /// <summary>
        /// 判斷窗體是否打開
        /// </summary>
        /// <param name="appName"></param>
        /// <returns></returns>
        private bool isOpen(string appName)
        {
            FormCollection collection = Application.OpenForms;
            foreach (Form form in collection)
            {
                if (form.Name == appName)
                {
                    return true;
                }
            }
            return false;
        }

    }
}      

Quartz 每次執行時都會重新執行個體化一個類, 是以Job類中的非靜态變量不能存儲狀态資訊.如何要儲存狀态資訊可以用靜态變量進行處理,也可以用參數值進行傳入傳出來實作。

3 JobListener

下面通過實作一個接口IJobListener來完成監聽器,其中包含任務執行前、執行中和執行後的方法,可以在對應方法中根據業務場景來進行定制,相關示例如下所示:

using System;
using Common.Logging;
using Quartz;
using Quartz.Impl;
using Quartz.Job;
namespace QuartzDemo
{
    public class JobListener : IJobListener
    {

        public virtual string Name
        {
            get { return "JobListener"; }
        }

        public virtual void JobToBeExecuted(IJobExecutionContext inContext)
        {
            //執行前執行
            Console.WriteLine("JobToBeExecuted");
        }

        public virtual void JobExecutionVetoed(IJobExecutionContext inContext)
        {
            //否決時執行
            Console.WriteLine("JobExecutionVetoed");
        }

        public virtual void JobWasExecuted(IJobExecutionContext inContext, JobExecutionException inException)
        {
            JobKey jobKey = inContext.JobDetail.Key;
            // 擷取傳遞過來的參數
            JobDataMap data = inContext.JobDetail.JobDataMap;
            //擷取回傳的資料庫表條目數
            int rowCount = data.GetInt(JobWithParameters.RowCount);

            try
            {
                if (rowCount > 9)
                {
                    inContext.Scheduler.PauseAll();
                    System.Windows.Forms.MessageBox.Show("預警已超9條");
                    inContext.Scheduler.ResumeAll();

                }
                Console.WriteLine(rowCount.ToString());
            }
            catch (SchedulerException e)
            {

                Console.Error.WriteLine(e.StackTrace);
            }
        }

    }
}      

4 效果

執行此示例,修改相關的資料,預警規則定期執行,則巡檢資料,如有符合預警的資料,則進行預警。具體如下圖所示:

Quartz.NET開源作業排程架構系列(三):IJobExecutionContext 參數傳遞
Quartz.NET開源作業排程架構系列(三):IJobExecutionContext 參數傳遞