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