Related: Quartz Clustering - triggers duplicated when the server starts在集羣環境中
創建石英觸發器我使用Quartz調度在基於Java的集羣環境管理計劃的作業。羣集中有幾個節點在任何時候都運行Quartz,由所有節點連接到的postgresql數據庫中的數據存儲支持。
當一個實例初始化,它試圖創建或更新工作,並通過執行該代碼在石英數據存儲觸發:
private void createOrUpdateJob(JobKey jobKey, Class<? extends org.quartz.Job> clazz, Trigger trigger) throws SchedulerException {
JobBuilder jobBuilder = JobBuilder.newJob(clazz).withIdentity(jobKey);
if (!scheduler.checkExists(jobKey)) {
// if the job doesn't already exist, we can create it, along with its trigger. this prevents us
// from creating multiple instances of the same job when running in a clustered environment
scheduler.scheduleJob(jobBuilder.build(), trigger);
log.error("SCHEDULED JOB WITH KEY " + jobKey.toString());
} else {
// if the job has exactly one trigger, we can just reschedule it, which allows us to update the schedule for
// that trigger.
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
if (triggers.size() == 1) {
scheduler.rescheduleJob(triggers.get(0).getKey(), trigger);
return;
}
// if for some reason the job has multiple triggers, it's easiest to just delete and re-create the job,
// since we want to enforce a one-to-one relationship between jobs and triggers
scheduler.deleteJob(jobKey);
scheduler.scheduleJob(jobBuilder.build(), trigger);
}
}
這種方法解決了許多問題:
- 如果環境配置不正確(即作業/觸發器不存在),那麼它們將通過第一個實例創建,它將啓動
- 如果作業已經存在,但我想修改其時間表(更改jo b每7分鐘運行一次,現在每5分鐘運行一次),我可以爲它定義一個新的觸發器,重新部署將重新安排數據庫中的觸發器
- 將創建一個作業的實例,因爲我們始終使用由作業本身定義的指定JobKey來引用作業。這意味着作業(及其關聯的觸發器)只創建一次,而不管集羣中有多少個節點,或者部署多少次。
這一切都很好,但我關心兩個實例在同一時間啓動時潛在的競爭條件。因爲這個代碼沒有集羣中所有節點都會尊重的全局鎖定,所以如果兩個實例同時聯機,那麼最終可能會出現重複的作業或觸發器,這會破壞此代碼的重點。
在羣集環境中自動定義Quartz作業和觸發器是否有最佳做法?或者我需要訴諸設置自己的鎖?
這並不是我正在尋找的東西,因爲它不會阻止Quartz爲同一個作業創建多個觸發器,但它確保只有其中一個觸發器會在給定的窗口,所以我認爲它確實解決了問題,如果以一種迂迴的方式。 – MusikPolice