Quartz 第三課 More About Jobs & JobDetails(官方文檔翻譯)

當學完第二課以後,你欣喜的發現,讓jobs工做起來是仍是至關簡單的。雖然讓jobs運行起來很簡單,對於其執行的關鍵內容仍是須要知道的。它們是IJob接口中的Execute和JobDetails。程序員

 

當你定義一個實現IJob接口的類的時候,你須要在裏面實現實際須要執行的代碼。Quartz.NET須要知道關於這代碼的各類信息,這樣 Quartz.NET才能像你指望的那樣工做。這些細節是在JobDetail類中進行了描述,在上一節以及進行了簡單的描述。安全

 

JobDetail由JobBuilder進行實例化的。JobBuilder允許開發人員使用 fluent interface.進行自定義JobDetail細節。併發

 

讓咱們花點時間看Job的機制以及在Quartz.NET中的生命週期。在第一節中已經看到的例子讓咱們再看一遍:ide

 1 // define the job and tie it to our HelloJob class
 2 IJobDetail job = JobBuilder.Create<HelloJob>()
 3     .WithIdentity("myJob", "group1")
 4     .Build();
 5 
 6 // Trigger the job to run now, and then every 40 seconds
 7 ITrigger trigger = TriggerBuilder.Create()
 8   .WithIdentity("myTrigger", "group1")
 9   .StartNow()
10   .WithSimpleSchedule(x => x
11       .WithIntervalInSeconds(40)
12       .RepeatForever())
13   .Build();
14   
15 sched.ScheduleJob(job, trigger);
View Code

如今定義一個HelloJob 以下所示:函數

1 public class HelloJob : IJob
2 {
3     public void Execute(IJobExecutionContext context)
4     {
5         Console.WriteLine("HelloJob is executing.");
6     }
7 }

請注意,在這裏給scheduler 一個IJobDetail 實例,它只須要一個job實例就能進行運行。當scheduler執行job的時候,scheduler 會在調用Execute方法以前實例化一個job實例。 能實例化job的前提是job類中須要有個無參的構造函數。還有一個須要注意的是,在job類中定義任何數據字段其實沒有什麼太大的意義,由於在job的運行期間不會保留這些數據字段。ui

 

看到這你或許會問,那我如何爲一個job提供屬性和配置信息呢?而且這麼能跟蹤保持job的執行狀態呢?要回答這些問題,關鍵要弄懂JobDataMap,它是JobDetail中的一部分。編碼

 

JobDataMap

JobDataMap中可用於容納任何數量的您但願提供給job實例在執行時(可序列化)的對象。JobDataMap實現了IDictionary接口,併爲其添加了一些用於存儲和檢索基本類型的數據的實用方法。spa

 

下面是JobDataMap 快速上手代碼,在添加job到scheduler以前先爲JobDataMap添加一些數據 :設計

1 // define the job and tie it to our DumbJob class
2 IJobDetail job = JobBuilder.Create<DumbJob>()
3     .WithIdentity("myJob", "group1") // name "myJob", group "group1"
4     .UsingJobData("jobSays", "Hello World!")
5     .UsingJobData("myFloatValue", 3.141f)
6     .Build();

下面是從執行的job中獲取JobDataMap 數據code

 1 Getting Values from a JobDataMap
 2 public class DumbJob : IJob
 3 {
 4     public void Execute(JobExecutionContext context)
 5     {
 6       JobKey key = context.JobDetail.Key;
 7 
 8       JobDataMap dataMap = context.JobDetail.JobDataMap;
 9 
10       string jobSays = dataMap.GetString("jobSays");
11       float myFloatValue = dataMap.GetFloat("myFloatValue");
12 
13       Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
14     }
15 }

若是你準備使用一個持久的JobStore (JobStore 將在JobStore 部分進行討論)你應該關注將在JobDataMap放些什麼。由於它會被序列化,因此更容易產生版本問題。在標準的版本中是安全的,除此以外,任何人均可以改變你的實體類。因此不得不關心兼容性會被破壞的狀況。

 

因此你能夠把AdoJobStore and JobDataMap 放進map中,僅包含着原始函數與字符串數據,所以消除了序列化的各類問題。

 

因爲Quartz默認JobFactory會再job實例化的時候去實例那些帶有set屬性的,因此當你添加帶有set訪問的屬性的時候會在JobDataMap中建立對應的key將其保存。這樣就不要進行顯示區指示在execute方法方法中進行映射。

 

Trigger也有其相關的JobDataMap。當你須要多個Trigger進行調度和重複scheduler 這是很是有用的。每一個Trigger是獨立的,而且須要你單獨輸入配置信息。

 

JobDataMap 將JobExecutionContext 做爲job執行時候的上下文。它裏面包含了JobDataMap 和Trigger而且覆蓋前面相同的值。

 

下面是來自JobExecutionContext獲取數據的做業執行過程當中合併的JobDataMap的一個簡單的例子:

 1 public class DumbJob : IJob
 2 {
 3     public void Execute(IJobExecutionContext context)
 4     {
 5         JobKey key = context.JobDetail.Key;
 6 
 7         JobDataMap dataMap = context.MergedJobDataMap;  // Note the difference from the previous example
 8 
 9         string jobSays = dataMap.GetString("jobSays");
10         float myFloatValue = dataMap.GetFloat("myFloatValue");
11         IList<DateTimeOffset> state = (IList<DateTimeOffset>) dataMap["myStateData"];
12         state.Add(DateTimeOffset.UtcNow);
13 
14         Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
15     }
16 }
View Code

或者,若是你想依靠的JobFactory「注入數據映射值到你的類,它可能看起來像這個:

 1 public class DumbJob : IJob
 2 {
 3     public string JobSays { private get; set; }
 4     public float FloatValue { private get; set; }
 5       
 6     public void Execute(IJobExecutionContext context)
 7     {
 8         JobKey key = context.JobDetail.Key;
 9 
10         JobDataMap dataMap = context.MergedJobDataMap;  // Note the difference from the previous example
11 
12         IList<DateTimeOffset> state = (IList<DateTimeOffset>) dataMap["myStateData"];
13         state.Add(DateTimeOffset.UtcNow);
14 
15         Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + JobSays + ", and val is: " + FloatValue);
16     }
17 }
View Code

你會注意到類的整個代碼較長,但在execute()方法的代碼是乾淨。人們還能夠爭辯說,雖然代碼越長,它實際上花了更少的編碼,若是程序員的IDE用於自動生成的屬性,而沒必要手工編寫單獨的調用從JobDataMap中檢索值。這是你的選擇。

Job 「Instances」

不少用戶花費時間是困惑到底是什麼構成了「Job實例」。咱們會盡力講清楚這裏,下面有關的工做狀態和併發性的部分。

 

您能夠建立一個job類,並經過建立JobDetails的多個實例的調度中存儲了不少實例定義」 - 每個都有本身的屬性和JobDataMap - 而且他們都增長到scheduler中

 

例如,你能夠建立一個實現所謂的「SalesReportJob」IJob接口的類。這個job可能會被編碼到指望發送給它(經過JobDataMap中)來指定銷售報告應根據銷售人員的姓名參數。而後它們能夠建立多個定義的jobJobDetails),如「SalesReportForJoe」「SalesReportForMike」具備joe」「Mike」在相應JobDataMaps做爲輸入到各自的job指定。

 

Trigger啓動,將一個JobDetail(實例定義),它會被自動加載,和job類是指經過對調度配置的JobFactory實例化。默認的JobFactory只是調用使用Activator.CreateInstance 調用job類的默認構造函數,而後嘗試在匹配的JobDataMap中的鍵名該類調用setter屬性。您可能但願建立本身的實現的JobFactory來完成的事情,如讓你的應用程序的IoC或者DI容器產生/初始化做業實例。

 

In 「Quartz speak」, 咱們指的是每一個存儲的JobDetail做爲「job定義」或「的JobDetail實例」,咱們指的是每個執行job做爲「job實例」或「job定義實例」。一般,若是咱們只是用這個詞的「job」,咱們指的是一個名爲定義或JobDetail等。當咱們指的是類實現job接口,咱們平時使用的術語「job type」。

Job State and Concurrency

如今有一些關於Job的狀態數據(aka JobDataMap)和併發性附加說明。能夠天劍組合特性到你的job類上,來影響Quartz’的行爲。

 

DisallowConcurrentExecution添加到Job類,告訴Quartz不執行給定的job定義的多個實例(便是指給定的job類)併發的屬性。注意這裏面的所說,必須當心使用。在上一節的例子中,若是「SalesReportJob」有這個屬性,比只有一個「SalesReportForJoe」的實例能夠在給定時間執行的,但它能夠與「SalesReportForMike」的一個實例,同時執行。約束是基於一個實例定義(JobDetail等),而不是在工做類的實例。可是,它(quartz的設計),決定對類自己攜帶的屬性,由於它決定對類進行怎樣進行編譯。

 

PersistJobDataAfterExecution是能夠被添加到Job類,告訴quartz更新JobDetailJobDataMap存儲的副本屬性在execute()方法成功完成後(未拋出異常),使得一樣的job在下一次執行(JobDetail)接收,而不是原先存儲的值的更新的值。像DisallowConcurrentExecution屬性,這適用於做業定義實例,而不是一個做業類的實例,雖然當時決定讓job類攜帶的屬性,由於它每每使對類是如何編碼的差別(如'有狀態'將須要顯式地理解的執行方法中的代碼)。

 

若是使用PersistJobDataAfterExecution屬性,你應該認真考慮也使用DisallowConcurrentExecution屬性,以免留下什麼數據時,一樣的job(JobDetail)的兩個實例併發執行存儲可能的混淆(競爭條件)

Other Attributes Of Jobs

下面是可用於經過JobDetail等對象的job實例來定義的其餘屬性的簡單總結:

 

持久性 - 若是job是不可持久的,它會自動從調度中刪除,一旦再也不有與之相關的任何活動的觸發器。換句話說,非持久job具備一個壽命由其觸發的存在的限制。

可恢復性 - 若是做業要求恢復,它是在調度的硬關閉的時間執行(即它崩潰中運行的過程當中,或在機器關閉),而後從新執行當調度程序從新開始。在這種狀況下,JobExecutionContext.Recovering屬性將返回真。

JobExecutionException

最後,咱們須要告訴你的IJob.Execute..)方法的一些細節。你應該從執行方法拋出的惟一類型是JobExecutionException。正由於如此,你一般應該換execute方法的所有內容以'try-catch「塊。你也應該花一些時間看的JobExecutionException的文檔,你的工做能夠用它來提供調度各類指令爲你想怎麼異常進行處理。

相關文章
相關標籤/搜索