程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> Quartz.NET開源作業調度框架系列(五):AdoJobStore保存job到數據庫,

Quartz.NET開源作業調度框架系列(五):AdoJobStore保存job到數據庫,

編輯:C#入門知識

Quartz.NET開源作業調度框架系列(五):AdoJobStore保存job到數據庫,


  Quartz.NET 任務調度的核心元素是 scheduler, trigger 和 job,其中 trigger(用於定義調度時間的元素,即按照什麼時間規則去執行任務) 和 job 是任務調度的元數據,scheduler 是實際執行調度的控制器。在Quartz.NET中主要有兩種類型的 job:無狀態的(stateless)和有狀態的(stateful)。對於同一個 trigger 來說,有狀態的 job 不能被並行執行,只有上一次觸發的任務被執行完之後,才能觸發下一次執行。無狀態任務一般指可以並發的任務,即任務之間是獨立的,不會互相干擾。一個 job 可以被多個 trigger 關聯,但是一個 trigger 只能關聯一個 job。某些任務需要對數據庫中的數據進行增刪改處理 , 這些任務不能並發執行,就需要用到無狀態的任務 , 否則會造成數據混亂。

  另外有些情況下,我們需要將任務保存到數據庫中,特別是有些任務中包含參數,例如累加的任務,如果可以保存到數據庫中,即便中間斷電或者程序異常重啟,中間計算的結果也不會丟失,可以從斷點的結果進行運算(首先恢復任務),下面介紹一下如何用AdoJobStore將任務保存到SQL Server數據庫中. 

  事先要在數據庫上新建一個QRTZ_數據庫,並執行SQL建表腳本:

1 RecoveryJob

  是一個無狀態的任務,代碼如下:

 1 using System;
 2 using System.Collections.Specialized;
 3 using System.Threading;
 4 using Common.Logging;
 5 using Quartz;
 6 using Quartz.Impl;
 7 using Quartz.Job;
 8 using System.Windows.Forms;
 9 namespace  QuartzDemo
10 {
11     /// <summary>
12     /// 無狀態的可恢復的任務
13     /// </summary>
14     public class RecoveryJob : IJob
15     {
16        
17         private const string Count = "count";
18         public virtual void Execute(IJobExecutionContext context)
19         {
20 
21             JobKey jobKey = context.JobDetail.Key;
22             if (isOpen("FrmConsole"))
23             {
24                 try
25                 {
26                     //獲取當前Form1實例
27                     __instance = (FrmConsole)Application.OpenForms["FrmConsole"];
28                     // 如果任務是恢復的任務的話
29                     if (context.Recovering)
30                     {
31                         __instance.SetInfo(string.Format("{0} RECOVERING at {1}", jobKey, DateTime.Now.ToString("r")));
32                     }
33                     else
34                     {
35                         __instance.SetInfo(string.Format("{0} starting at {1}", jobKey, DateTime.Now.ToString("r")));
36                     }
37 
38                     JobDataMap data = context.JobDetail.JobDataMap;
39                     int count;
40                     if (data.ContainsKey(Count))
41                     {
42                         //是否能從數據庫中恢復,如果保存Job等信息的話,程序運行突然終端(可用調試時中斷運行,而不是關閉窗體來模擬)
43                         count = data.GetInt(Count);
44                     }
45                     else
46                     {
47                         count = 0;
48                     }
49                     count++;
50                     data.Put(Count, count);
51 
52                     __instance.SetInfo(string.Format(" {0} Count #{1}", jobKey, count));
53                 }
54                 catch (Exception ex)
55                 {
56                     Console.WriteLine(ex.Message);
57                 }
58             }
59         }
60 
61 
62         private static FrmConsole __instance = null;
63 
64         /// <summary>
65         /// 判斷窗體是否打開
66         /// </summary>
67         /// <param name="appName"></param>
68         /// <returns></returns>
69         private bool isOpen(string appName)
70         {
71             FormCollection collection = Application.OpenForms;
72             foreach (Form form in collection)
73             {
74                 if (form.Name == appName)
75                 {
76                     return true;
77                 }
78             }
79             return false;
80         }
81 
82     }
83 }

2 RecoveryStatefulJob

  是一個有狀態的任務,和無狀態的區別就是在任務類的上面用[PersistJobDataAfterExecution]標注任務是有狀態的 , 有狀態的任務不允許並發執行,也需要標注 [DisallowConcurrentExecution],代碼如下:

 1 using System;
 2 using System.Collections.Specialized;
 3 using System.Threading;
 4 using Common.Logging;
 5 using Quartz;
 6 using Quartz.Impl;
 7 using Quartz.Job;
 8 using System.Windows.Forms;
 9 namespace  QuartzDemo
10 {
11     /// <summary>
12     ///  用這個[PersistJobDataAfterExecution]標注任務是有狀態的,
13     ///  有狀態的任務不允許並發執行 [DisallowConcurrentExecution]
14     /// </summary>
15     [PersistJobDataAfterExecution]
16     [DisallowConcurrentExecution]
17     public class RecoveryStatefulJob : RecoveryJob
18     {
19 
20     }
21 }

3 AdoJobStoreExample

   用 properties["quartz.dataSource.default.connectionString"] = "Server=(local);Database=QRTZ_;Trusted_Connection=True;";定義了數據庫的連接信息,程序運行時會自動將任務保存到數據庫中:

  1 using System;
  2 using System.Collections.Specialized;
  3 using System.Threading;
  4 using Common.Logging;
  5 using Quartz;
  6 using Quartz.Impl;
  7 using Quartz.Job;
  8 using System.Windows.Forms;
  9 namespace QuartzDemo
 10 {
 11     /// <summary> 
 12     ///  AdoJobStore的用法示例
 13     /// </summary>
 14     public class AdoJobStoreExample 
 15     {
 16         public virtual void Run(bool inClearJobs, bool inScheduleJobs)
 17         {
 18             NameValueCollection properties = new NameValueCollection();
 19 
 20             properties["quartz.scheduler.instanceName"] = "TestScheduler";
 21             properties["quartz.scheduler.instanceId"] = "instance_one";
 22             properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
 23             properties["quartz.threadPool.threadCount"] = "5";
 24             properties["quartz.threadPool.threadPriority"] = "Normal";
 25             properties["quartz.jobStore.misfireThreshold"] = "60000";
 26             properties["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz";
 27             properties["quartz.jobStore.useProperties"] = "false";
 28             properties["quartz.jobStore.dataSource"] = "default";
 29             properties["quartz.jobStore.tablePrefix"] = "QRTZ_";
 30             properties["quartz.jobStore.clustered"] = "true";
 31             // SQLite
 32             // properties["quartz.jobStore.lockHandler.type"] = "Quartz.Impl.AdoJobStore.UpdateLockRowSemaphore, Quartz";
 33             properties["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz";
 34     // 數據庫連接字符串
 35             properties["quartz.dataSource.default.connectionString"] = "Server=(local);Database=QRTZ_;Trusted_Connection=True;";
 36             properties["quartz.dataSource.default.provider"] = "SqlServer-20";
 37 
 38             // First we must get a reference to a scheduler
 39             ISchedulerFactory sf = new StdSchedulerFactory(properties);
 40             IScheduler sched = sf.GetScheduler();
 41 
 42             bool b是否恢復 = false;
 43             if (inClearJobs)
 44             {
 45                Console.WriteLine("***** Deleting existing jobs/triggers *****");
 46                // sched.Clear();
 47             }
 48 
 49          
 50             if (inScheduleJobs)
 51             {
 52              
 53                 string schedId = sched.SchedulerInstanceId;
 54 
 55                 int count = 1;
 56 
 57                 //定義一個無狀態的任務
 58                 IJobDetail job = JobBuilder.Create<RecoveryJob>()
 59                     .WithIdentity("recoveryjob_" + count, schedId) 
 60                     .RequestRecovery() //recovery
 61                     .Build();
 62 
 63 
 64                 ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create()
 65                                                               .WithIdentity("triger_" + count, schedId)
 66                                                               .StartAt(DateBuilder.FutureDate(1, IntervalUnit.Second))
 67                                                               .WithSimpleSchedule(x => x.WithRepeatCount(20).WithInterval(TimeSpan.FromSeconds(3)))
 68                                                               .Build();
 69                 //可用此來查看定義的觸發器觸發規則
 70                 //log.InfoFormat("{0} will run at: {1} and repeat: {2} times, every {3} seconds", 
 71                 //job.Key, trigger.GetNextFireTimeUtc(), 
 72                 //trigger.RepeatCount, 
 73                 //trigger.RepeatInterval.TotalSeconds);
 74                 try
 75                 {
 76                     //如果數據庫已經存在同名job和trigger,則綁定失敗
 77                     sched.ScheduleJob(job, trigger);
 78                 }
 79                 catch
 80                 {
 81                     b是否恢復 = true;
 82                 }
 83                 count++;
 84 
 85                 //定義一個有狀態的任務***********************************************************
 86                 job = JobBuilder.Create<RecoveryStatefulJob>()
 87                     .WithIdentity("Statefuljob_" + count, schedId)
 88                     .RequestRecovery() // recovery
 89                     .Build();
 90 
 91                 trigger = (ISimpleTrigger)TriggerBuilder.Create()
 92                                                .WithIdentity("triger_" + count, schedId)
 93                                                .StartAt(DateBuilder.FutureDate(1, IntervalUnit.Second))
 94                                                .WithSimpleSchedule(x => x.WithRepeatCount(20).WithInterval(TimeSpan.FromSeconds(3)))
 95                                                .Build();
 96           
 97                 try
 98                 {
 99                     sched.ScheduleJob(job, trigger);
100                 }
101                 catch
102                 {
103                     b是否恢復 = true;
104                 }
105 
106 
107                
108             }
109         
110             //啟動
111             sched.Start();
112             //sched.Shutdown();
113 
114         }
115 
116         public string Name
117         {
118             get { return GetType().Name; }
119         }
120 
121         public void Run()
122         {
123             bool clearJobs = true;
124             //clearJobs = false;
125             bool scheduleJobs = true;
126             AdoJobStoreExample example = new AdoJobStoreExample();
127             example.Run(clearJobs, scheduleJobs);
128         }
129     }
130 }

 

  可以看到有狀態的計數每次累加1,而無狀態的每次執行時都會丟失累加數(新的實例),中斷程序,查看數據庫的QRTZ_JOB_DETAILS表,可以看見還有一個持久化的任務:

  中斷程序後(調試狀態時不關閉窗體,而是中斷調試,模擬異常關閉) ,再重新運行可以看到如下界面:

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved