Quartz.NET 2.x 文件翻譯 - Lesson 3:Jobs 和 Triggers深入瞭解
Quartz.NET 2.x 文件翻譯 - Lesson 3:Jobs 和 Triggers深入瞭解 檢視官網英文原文
正如我們在第2章說到的,我們可以很容易的執行一個job任務,那麼接下來需要我們瞭解知道的job深入內容主要有IJob介面的Execute()方法和JobDetails。
對於一個job任務來說,我們知道如何制定特定type型別和如何編寫實現一個job的程式碼,對於使用Quartz.NET來說我們需要了解它各種各樣的屬性引數,那麼肯定希望有這方面的demo例子了,正如我們上一章說過的,可以通過job的JobDetail明細類來進行分析。
JobDetail明細類的例項是通過JobBuilder建立的,JobBuilder允許我們使用連續的介面方式進行實現和編碼。
我們還是用quartz.net的生命週期程式碼來分析,正如上幾章節提到的程式碼:
Using Quartz.NET
// define the job and tie it to our HelloJob class IJobDetail job = JobBuilder.Create<HelloJob>() .WithIdentity("myJob", "group1") .Build(); // Trigger the job to run now, and then every 40 seconds ITrigger trigger = TriggerBuilder.Create() .WithIdentity("myTrigger", "group1") .StartNow() .WithSimpleSchedule(x => x .WithIntervalInSeconds(40) .RepeatForever()) .Build(); sched.ScheduleJob(job, trigger);
接下來定義一個job實現類HelloJob:
public class HelloJob : IJob { public void Execute(IJobExecutionContext context) { Console.WriteLine("HelloJob is executing."); } }
注意這裡,我們提供給scheduler排程的是一個IJobDetail介面,通過引用關係,job的實現類引用來執行任務的。每次scheduler排程執行job任務的時候,排程會在執行Execute方法前建立一個新的實現類,然後繼續執行方法,這就要求我們每一個job任務實現類都需要一個自身建構函式,另外就是在job任務例項類中定義資料儲存欄位屬性等操作是無意義的,因為job執行過程中並不會進行儲存。
說到這裡,也許你會想問“那我怎麼才能給一個job任務例項化類設定一些屬性或者配置呢?”或者“我如何才能跟蹤記錄job任務狀態在執行間隔?”,答案就是:JobDataMap中的key值,也就是JobDetail物件的包含屬性內容中。
JobDataMap
JobDataMap可以儲存容納任意數量的可序列化物件,以便在job例項化執行的時候使用。JobDataMap是IDictionary介面的實現,並新增了一些方便儲存和檢索原始型別資料的方法。
下面演示一小段程式碼來說明將job任務新增到scheduler排程前先將資料新增到JobDataMap:
Setting Values in a JobDataMap
// define the job and tie it to our DumbJob class IJobDetail job = JobBuilder.Create<DumbJob>() .WithIdentity("myJob", "group1") // name "myJob", group "group1" .UsingJobData("jobSays", "Hello World!") .UsingJobData("myFloatValue", 3.141f) .Build();
下面演示下job任務執行時候從JobDataMap中取出資料的程式碼片段:
Getting Values from a JobDataMap
public class DumbJob : IJob { public void Execute(JobExecutionContext context) { JobKey key = context.JobDetail.Key; JobDataMap dataMap = context.JobDetail.JobDataMap; string jobSays = dataMap.GetString("jobSays"); float myFloatValue = dataMap.GetFloat("myFloatValue"); Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue); } }
如果想保持持久化的資料,我們需要注意哪些放置到JobDataMap中,因為物件會被序列化,這很容易帶來版本問題。很明顯,標準的.net型別理論是安全的,但除此之外,已經序列化的類中任意一個屬性的變化,都有可能導致物件資訊的不完整和不準確。
當然,我們也可以將adojobstore和JobDataMap組合成一個model模型,只能儲存string和原始資料庫型別,以此來消除可能出現的序列化問題。
如果我們新增設定了和JobDataMap中的key的name值相同的屬性到job任務class類中,然後quartz的JobFactory會預設自動呼叫這些設定屬性在job任務類例項化的時候,因此,我們要明確的從執行方法中取出我們需要的數值。
Trigger觸發器也有JobDataMaps,在我們需要定時排程執行一個重複性的job任務的時候,就用到Trigger觸發器的JobDataMaps了,對於獨立的Trigger觸發器來說我們就需要提供不同的data資料給job任務。
JobDataMap是在job任務執行過程中由JobExecutionContext當做載體儲存的,這其實是Trigger觸發器和jobdetail任務詳細的一個合併而成的JobDataMap,後者根據相同的name屬性重寫了對應的value值。
下面演示資料從JobExecutionContext在job執行過程中合併JobDataMap的過程:
public class DumbJob : IJob { public void Execute(IJobExecutionContext context) { JobKey key = context.JobDetail.Key; JobDataMap dataMap = context.MergedJobDataMap; // Note the difference from the previous example string jobSays = dataMap.GetString("jobSays"); float myFloatValue = dataMap.GetFloat("myFloatValue"); IList<DateTimeOffset> state = (IList<DateTimeOffset>) dataMap["myStateData"]; state.Add(DateTimeOffset.UtcNow); Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue); } }
或者我們也可以使用JobFactory的依賴注入方式,將資料對映到class中,如下程式碼:
public class DumbJob : IJob { public string JobSays { private get; set; } public float FloatValue { private get; set; } public void Execute(IJobExecutionContext context) { JobKey key = context.JobDetail.Key; JobDataMap dataMap = context.MergedJobDataMap; // Note the difference from the previous example IList<DateTimeOffset> state = (IList<DateTimeOffset>) dataMap["myStateData"]; state.Add(DateTimeOffset.UtcNow); Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + JobSays + ", and val is: " + FloatValue); } }我們發現整體程式碼量增加了,但是我們的執行方法execute()變得簡潔了。還有人認為程式碼量增加了,但是編碼更加容易了,如果程式碼都是我們們平時的IDE生成的屬性等,而不用我們手寫程式碼取出JobDataMap的數值,那麼這樣的程式碼才算是整潔有效。
Job “Instances”
很多人可能會有疑惑到底是什麼構成了一個個的job任務例項,接下來我們就儘量清晰的講解清楚job任務的狀態和併發等情況。
我們可以建立一個簡單的job任務類,然後建立幾個例項JobDetails,每個例項都有自己設定的屬性和JobDataMap,然後把這些例項新增到scheduler排程。
比如,我們可以建立一個實現了IJob介面的SalesReportJob類,然後新增程式碼,實現通過傳入的引數,如銷售人員名稱實現將對應銷售人員的銷售報表傳送給他,我們也可以建立很多的JobDetails,比如salesreportforjoe或者salesreportformike來區分joe和mike,然後根據JobDataMaps的引數來區分那個job任務進行執行處理。
當一個Trigger觸發器被觸發後,JobDetail會被載入,job任務類在通過JobFactory配置實現排程程式。預設JobFactory只呼叫使用job工作類的預設建構函式。CreateInstance方法會嘗試在JobDataMap中呼叫相匹配的key的names,也許你想建立自己的JobFactory實現,來實現類似於IOC、DI容器等job任務的功能。
對於“Quartz”來說,我們把指定的每個儲存JobDetail明細當做是一個job任務類定義或者是JobDetail明細類定義,或是我們執行的每個job任務類定義、job實現定義。
通常我們僅僅使用job任務這個詞來表明一個job任務類定義或是一個JobDetail的明細而已。當我們需要實現job介面的時候,我們通常使用“job type”這個詞語。
Job State and Concurrency
下面,有一些關於job任務工作狀態資料的一些附加說明(又名JobDataMap)和併發的資訊,有一對屬性可以新增到我們的job任務類中,這一對屬性可以影響Quartz的執行併發等方面。DisallowConcurrentExecution 是其中一個屬性,可以新增到job任務類,來通知quartz不同時執行我們給定的一個job任務的多個例項。這裡使用的時候一定要注意。在我們前面說過的章節裡面,如果SalesReportJob這個job任務類設定了這個屬性,那麼只能是SalesReportForJoe的一個例項能執行在任務執行時間點,但是我們也可以在執行一個SalesReportForJoe例項的同時執行SalesReportForMike的一個例項。這個約束基於JobDetail的例項而不是job任務類,然而這個約束在quartz的設計過程中又建立在class類本身,因為class的編碼有各種不同之處。
PersistJobDataAfterExecution 是另外一個屬性,可以實現在Execute()方法執行併成功後通知quartz更新儲存從JobDetail的任務明細JobDataMap資料,這樣再次執行同一個job任務的時候就會使用update更新後的資料而不是原來的舊資料了。和DisallowConcurrentExecution屬性一樣,這個屬性也是應用在job定義中,而不是job的class中,雖然在我們編碼過程中它也是在job的class中去設定的屬性。
如果我們使用PersistJobDataAfterExecution屬性,我們需要考慮清楚一併使用DisallowConcurrentExecution屬性,以此避免多個例項執行job的時候,新舊資料儲存的併發問題。
Other Attributes Of Jobs
還有一些JobDetail其他的屬性:
Durability - 如果一個job工作是非持久的,那麼它會自動從scheduler排程中刪除在沒有任何活動的triggers觸發與它相關聯的時候。換言之,非持久的job任務是有生命週期,這取決於它的觸發器的是否存在。
RequestsRecovery - 如果一個job“RequestsRecovery”,它是在排程執行過程中被強制關閉的(比如執行崩潰或是機器斷電等),那麼它會從新執行在scheduler排程重新啟動後。在這種情況下JobExecutionContext.Recovering屬性將會返回true。
JobExecutionException
最後,簡單說下IJob.Execute(..)方法,該方法執行中的唯一的異常型別是JobExecutionException,因此,在我們編碼的時候,需要用try catch將整個方法包含在內,有空的話多看看和JobExecutionException相關的文件,以便在我們使用的時候能更好的執行各種命令並處理各種異常。
由龐順龍最後編輯於:3年前
內容均為作者獨立觀點,不代表八零IT人立場,如涉及侵權,請及時告知。
相關文章
- Quartz.NET 2.x 文件翻譯 - Lesson 2:Jobs 和 Triggersquartz
- Quartz.NET 2.x 文件翻譯 - Lesson 8:SchedulerListenersquartz
- Quartz.NET 2.x 文件翻譯 - Lesson 9:JobStoresquartz
- Quartz.NET 2.x 文件翻譯 - Lesson 4:更多Triggers觸發器說明quartz觸發器
- Quartz.NET 2.x 文件翻譯 - Lesson 1:使用Quartzquartz
- Quartz.NET 2.x 文件翻譯 - Lesson 7:TriggerListeners 和JobListenersquartz
- Quartz.NET 2.x 文件翻譯 - Lesson 10:Configuration, Resource Usage 和 SchedulerFactoryquartz
- Quartz.NET 2.x 文件翻譯 - Lesson 5:SimpleTrigger觸發模式quartz模式
- Quartz.NET 2.x 文件翻譯 - Lesson 12:Quartz的其他各種特性quartz
- Quartz.NET 2.x 文件翻譯 - Lesson 6:CronTrigger觸發模式quartz模式
- Quartz.NET 2.x 文件翻譯-文章目錄quartz
- Quartz.NET 2.x 文件翻譯 - Lesson 11:Advanced (Enterprise) Features 高階功能quartz
- [譯]HTML&CSS Lesson3: 瞭解CSSHTMLCSS
- docker官方文件翻譯3Docker
- [譯]HTML&CSS Lesson2: 瞭解HTMLHTMLCSS
- 深入理解Hystrix之文件翻譯
- [譯] 深入瞭解 FlutterFlutter
- 【翻譯】fancyBox3 中文文件
- 文件翻譯器怎麼用?如何翻譯Word文件?
- JavaPoet 文件翻譯Java
- [翻譯] 深入SaltStack
- 有ppt文件翻譯軟體嗎?如何翻譯整篇ppt文件
- MPAndroidChart文件翻譯Android
- Moya官方文件翻譯
- Samza文件翻譯 : Backgroud
- 本人翻譯的文件
- 實用的Word文件翻譯方法分享,讓Word文件快速翻譯
- 怎麼翻譯整篇Excel文件?Excel文件翻譯一招搞定Excel
- OkHttp3深入瞭解之InterceptorsHTTP
- 怎麼把Excel文件翻譯成中文?Excel文件翻譯方法介紹Excel
- SnapKit 中文文件翻譯APK
- docker官方文件翻譯4Docker
- rabbitmq 官方文件翻譯-2MQ
- docker官方文件翻譯5Docker
- docker官方文件翻譯2Docker
- docker官方文件翻譯1Docker
- Core Foundation 官方文件翻譯
- Samza文件翻譯 : Architecture