gpt4 book ai didi

java - 在集群环境中创建 Quartz 触发器

转载 作者:搜寻专家 更新时间:2023-11-01 03:34:04 25 4
gpt4 key购买 nike

Related: Quartz Clustering - triggers duplicated when the server starts

我正在使用 Quartz Scheduler 来管理基于 Java 的集群环境中的计划作业。在任何给定时间,集群中都有一些节点,它们都运行 Quartz,由所有节点连接到的 postgresql 数据库中的数据存储支持。

当实例初始化时,它会尝试通过执行以下代码在 Quartz 数据存储中创建或更新作业和触发器:

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);
}
}

这种方法解决了一些问题:

  1. 如果环境配置不正确(即作业/触发器不存在),那么它们将由启动的第一个实例创建
  2. 如果作业已经存在,但我想修改它的时间表(将过去每 7 分钟运行一次的作业更改为现在每 5 分钟运行一次),我可以为其定义一个新触发器,重新部署将重新安排数据库中的触发器
  3. 将创建一个作业实例,因为我们总是通过指定的 JobKey 来引用作业,该 JobKey 由作业本身定义。这意味着无论集群中有多少节点,或者我们部署了多少次,作业(及其关联的触发器)都只会创建一次。

一切都很好,但我担心两个实例同时启动时可能出现竞争条件。因为集群中的所有节点都遵守此代码周围没有全局锁定,所以如果两个实例同时联机,我可能会得到重复的作业或触发器,这在某种程度上违背了此代码的要点。

是否有在集群环境中自动定义 Quartz 作业和触发器的最佳实践?还是我需要求助于设置自己的锁?

最佳答案

我不确定在 Quartz 中是否有更好的方法来做到这一点。但如果您已经在使用 Redis 或 Memcache,我建议让所有实例执行 atomic increment。针对众所周知的 key 。如果您粘贴的代码应该在每个集群每小时只运行一个作业,您可以执行以下操作:

long timestamp = System.currentTimeMillis() / 1000 / 60 / 60;
String key = String.format("%s_%d", jobId, timestamp);

// this will only be true for one instance in the cluster per (job, timestamp) tuple
bool shouldExecute = redis.incr(key) == 1

if (shouldExecute) {
// run the mutually exclusive code
}

时间戳为您提供了一个移动窗口,在该窗口内作业竞争执行此作业。

关于java - 在集群环境中创建 Quartz 触发器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37171188/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com