本文來自對http://www.quartz-scheduler.org/documentation/best-practices.html的翻譯。html
表示還沒用過Quartz,正準備用的,而後在官網上看到了這個,而後以爲還挺短的,就翻譯一下。java
最佳實踐數據庫
對生產環境中使用Tips安全
任務數據映射Tips異步
觸發Tipsspa
JDBC的JobStore命令行
daylight savings time(這個翻譯是夏令時,因此我不知道怎麼翻譯了)線程
任務翻譯
監聽器(觸發監聽器,任務監聽器,調度監聽器)日誌
經過應用暴露調度器功能
生產環境中的建議
跳過更新檢查
Quartz在鏈接服務的時候包含了一個「更新檢查」的特性,這個特性會檢查是否有Quartz的新版本可用。
這個個檢查是異步進行的,並不會影響Quartz的啓動和初始化時間,若是鏈接失敗的話,它會優雅地結束。
若是運行了檢查,並且找到了新的版本,將會在Quartz的日誌中進行記錄。
你能夠將Quartz配置屬性設置org.quartz.scheduler.skipUpdateCheck: true或者將系統屬性org.terracotta.quartz.skipUpdateCheck=true(這個是在系統環境或者在java命令行中以-D加入),這樣就能夠禁用掉Quartz的更新檢查。建議你在生產環境的部署中禁用更新檢查。
任務數據映射的建議
在JobDataMap中僅僅存儲原始數據類型(包括Strings)
在JobDataMap中僅僅存儲原始數據類型(包括Strings)能夠避免短時間或長期的序列化的問題。
使用合併的JobDataMap
在任務執行的時候,JobExecutionContext中的JobDataMap做爲一個convenience。它是經過在JobDetail中的JobDataMap和Trigger中的JobDataMap合併而來,後者中的值會覆蓋前面一箇中同名變量的值。
當你有一個任務在scheduler中,並且這個任務又會被多個Triggers重複使用,那麼你最好把值存在Trigger的JobDataMap中,這樣對於每次獨立的任務觸發時,你就能夠爲Job提供不一樣的數據輸入啦。
根據以上所述,咱們提出了以下的最佳實踐:在調用Job.execute(...)方法時,通常來講應該從JobExecutionContext中的JobDataMap中解析變量的值,而不是直接從JobDetail的JobDataMap中解析。
觸發器建議
使用TriggerUtils
TriggerUtils:
提供了一個簡單的方法來建立triggers(schedules)
有不少不一樣的方法經過schedules來建立triggers以知足特定的描述,這個要比直接實例化特定類型的triggers(SimpleTrigger,CronTrigger等)而後調用不一樣的setter方法來配置它們方便許多
提供了一個簡單的方法來建立日期(好比start/end日期)
提供了分析triggers的助手(好比計算剩餘的觸發時間)
JDBC JobStore
永遠都不要直接往Quartz的表中寫數據
經過SQL直接往數據庫中寫入scheduling數據而不是經過API會形成一下問題:
會形成數據腐化(被刪除的數據,混亂的數據)
會形成任務在到達執行點的時候像沒有執行就消失了
會形成當觸發時間到來時,而任務還未執行
可能會形成死鎖
其餘奇怪的問題和數據腐化
永遠不要在同一個數據庫中將一個非集羣的調度器指向另外一個相同名字的調度器
若是你在同一套數據庫表中指定了多於一個的調度器實例,而且這些實例並非配置在集羣中,那麼下面的狀況將有可能會發生:
會形成數據腐化(被刪除的數據,混亂的數據)
會形成任務在到達執行點的時候像沒有執行就消失了
會形成當觸發時間到來時,而任務還未執行
可能會形成死鎖
其餘奇怪的問題和數據腐化
確保足夠的數據源中的鏈接數量
建議將你的數據源鏈接數配置爲配置爲線程池中工做線程數加3。若是你的應用還要常常調用scheduler的API,那麼你還須要增長額外的鏈接數量。若是你正在使用JobStoreCMT,那麼「未管理的」數據源的最大鏈接數至少爲4。
夏令時
避免將任務安排在接近夏令時的轉移時間
注意:本地的時鐘向前或者向後轉移時和總的時間的細節能夠在以下連接中找到:
https://secure.wikimedia.org/wikipedia/en/wiki/Daylight_saving_time_around_the_world.
SimpleTriggers不受夏令時的影響,這是由於它們老是在毫秒時刻被精確地觸發,而且在進過了精確的毫秒數以後會再次被觸發。
因爲CronTriggers會在給定的時/分/秒被觸發,當夏令時轉移時到來的時候,它們會受到這些怪事的影響。
舉一個可能發生的例子,在夏令時的美國時區/位置進行調度的時候,若是使用CronTrigger而且調度的觸發時間是在1:00 AM和2:00 AM之間時會發生下列的問題:
1:05 AM也許會發生兩次!可能會重複地觸發CronTrigger
2:05 AM也許永遠不會發生!可能會遺漏CronTrigger的觸發
同時,時間和調整量要根據當地位置來調節。
其餘的觸發器類型是根據日曆的移動而不是根據確切的時間量來進行的,例如CalenderIntervalTrigger,將會一樣地受影響,但不是錯過觸發或者觸發兩次,而是將它的觸發時間偏移一個小時。
Jobs
等待條件來到
長時間運行的任務會阻止其餘任務的運行(若是在線程池中全部的線程都繁忙)。
若是你認爲須要調用Thread.sleep()這個方法來中止工做線程執行任務,這是一個典型的信號,任務不會完成其他的任務,因它必須等待某些條件的到來(好比某些數據可讀)。
一個更好的方法是釋放線程(退出任務)而且容許其餘任務在這個線程執行。任務能夠從新調度本身,或者在它退出以前其餘任務。
拋出異常
一個任務的執行方法應該包含在try-catch塊中,以此處理可能發生的異常。
若是一個任務拋出一個異常,Quartz通常會立刻再執行它(可能會拋出相同的異常)。最好是任務捕獲全部它可能遇到的異常並處理它們,而後從新調度本身或其餘的任務。
可恢復性和冪等性
帶有"recoverable"的任務會在調度器失敗時從新執行。這意味着某些任務的工做將會被執行兩次。
這意味着在編寫任務的時候它的工做應該是冪等的。
監聽器(TriggerListener,JobListener,SchedulerListener)
保持編寫簡潔高效的監聽器
不建議在監聽器中完成大量的工做,由於將要執行任務的線程(或者完成觸發和引起另外一個任務等)將會綁定在監聽器上。
處理異常
每一個監聽器的方法都應該在try-catch塊中處理全部可能的異常。
若是一個監聽器拋出了一個異常,可能會形成其餘的監聽器沒法被通知到或阻止其餘任務的執行等。
經過應用來暴露調度器的功能
當心安全問題!
有的用戶經過應用程序接口來暴露Quartz的調度功能。這會很是有用,雖它可能會形成極度的危險。
確保你沒有錯誤地容許用戶定義他們想要的任何參數和任何類型的任務。例如,Quartz會帶有一個預約的任務org.quartz.jobs.NativeJob,這個任務將會在它們定義的任意的本地系統上執行命令。惡意的用戶可能會使用這個來控制或者摧毀你的系統。
一樣的像SendEmailJob之類的任務,而且事實上任何其餘的任務均可以被看成惡意用途。
若是容許用戶定義任意他們想要的任務將會是你的系統遭受各類可能的危害,等同於OWASP和MITRE定義的命令注入攻擊等。