前面寫了關于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 效果
執行此示例,修改相關的資料,預警規則定期執行,則巡檢資料,如有符合預警的資料,則進行預警。具體如下圖所示:
