Spring Boot 中使用 Quartz(三)優化版
今天要跟大家接續上次Spring Boot 中使用 Quartz(二)動態設定 Scheduler這篇文章。
不知道大家有發現嗎?如果我們的排程是每 30 秒一次,程式在啟動的時候會花很多時間,主要應該是花在排程表的 delete
與 insert
上。
今天就是跟大家講解一下,我後來的解決方案。
Quick Start
再進行之前,我們先來觀察一下上次的這張表
1 | select * from qrtz_cron_triggers |
我們可以發現,如果是 30 秒執行一次,我們只需要兩筆資料就可以了。
如:1
20 * * * * ?
30 * * * * ?
因此,我們將 SchedulerUtil.java
調整為:
另外,我將 JobBuilder
與 JobDetail
分開,因為我們可以在 JobBuilder
中添加我們想要的參數。
如:1
2jobBuilder.usingJobData(JOB_DATA_GAMETIME, (int) gameConfig.getGameTime())
.usingJobData(JOB_DATA_GAMETIMEOFFSET, (int) gameConfig.getGameTimeOffset());
驗證
1 | select * from qrtz_cron_triggers |
補充說明
1. 排程避免啟動時刪除 Job
因為我不希望在微服務的架構下,我們每次重新啟動服務的時候都會去刪除 Job
,因此我在 JobData
中加入我需要比對的參數判斷是否有異動與是否需要刪除 Job
1
2
3
4
5
6
7
8
9
10
11
12
13// 判斷是否有需要更新資料庫的排程
JobDetail oldJobDetail = scheduler.getJobDetail(jobDetail.getKey());
if(oldJobDetail!=null &&
gameConfig.getGameTime().toString().equals(oldJobDetail.getJobDataMap().get(JOB_DATA_GAMETIME).toString()) &&
gameConfig.getGameTimeOffset().toString().equals(oldJobDetail.getJobDataMap().get(JOB_DATA_GAMETIMEOFFSET).toString())) {
break;
} else {
log.info("刪除 scheduler.jobGroup : " + gameConfig.getId());
// 刪除舊的job
for (JobKey key : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(String.valueOf(gameConfig.getId())))) {
scheduler.deleteJob(key);
}
}
完整的程式請參考:
2. 時間過了就不想要在補啟動
由於 Quartz
有防火措施,當一個正常的 Job 錯過時間了,會進入防火措施的設定,你可以設定你的防火措施時間要多長與錯過了需要如何補救。
因為我是不想要有任何防火措施,所以我調整了以下:
設定防火時間
application.yml1
2
3
4
5
6
7spring:
quartz:
properties:
org:
quartz:
jobStore:
misfireThreshold: 500建立
CronTriger
時加上withMisfireHandlingInstructionDoNothing
,表示錯過了不做任何事。1
2
3
4Trigger trigger = TriggerBuilder.newTrigger().forJob(jobDetail)
.withIdentity(jobDetail.getKey().getName(), jobDetail.getKey().getGroup())
.withSchedule(CronScheduleBuilder.cronSchedule(cronExp).withMisfireHandlingInstructionDoNothing())
.build();
3. 科普
3.1 這邊幫大家科普一下 CronTriger
的三種狀態,分別是
withMisfireHandlingInstructionDoNothing :
不觸發執行,等待下次Cron觸發頻率到達時刻開始按照Cron頻率依次執行withMisfireHandlingInstructionIgnoreMisfires :
以錯過的第一個頻率時間立刻開始執行,重做錯過的所有頻率週期後,當下一次觸發頻率發生時間大於當前時間後,再按照正常的Cron頻率依次執行withMisfireHandlingInstructionFireAndProceed :
以當前時間為觸發頻率立刻觸發一次執行,然後按照Cron頻率依次執行
3.2 misfireThreshold
的 default
值是 60000
Donate
謝謝您的支持與鼓勵