我们正在运行Spring 3.0.x Web应用程序(.war),并在集群WebLogic 10.3.4环境中使用夜间@Scheduled作业。但是,当应用程序部署到每个节点时(使用AdminServer的Web控制台中的部署向导),每晚在每个节点上启动作业,从而同时运行多次。
我们如何防止这种情况发生?
我知道像Quartz这样的库允许通过数据库锁表来协调集群环境中的作业,或者我甚至可以自己实现类似的东西。但是,由于这似乎是一个相当普遍的情况,我想知道Spring是否还没有选择如何轻松地避免这个问题,而无需在我的项目中添加新库或手动处理变通方法。
如果有任何未解决的问题,请与我们联系。我还在Spring Community forums上提出了这个问题。非常感谢你的帮助。
答案 0 :(得分:5)
我们只有一项任务可以发送每日摘要电子邮件。为了避免额外的依赖关系,我们只需检查每个节点的主机名是否与已配置的系统属性相对应。
private boolean isTriggerNode() {
String triggerHostmame = System.getProperty("trigger.hostname");;
String hostName = InetAddress.getLocalHost().getHostName();
return hostName.equals(triggerHostmame);
}
public void execute() {
if (isTriggerNode()) {
//send email
}
}
答案 1 :(得分:3)
我们正在使用应用程序数据库中的共享锁表来实现我们自己的同步逻辑。这允许所有群集节点在实际启动它之前检查作业是否已在运行。
答案 2 :(得分:3)
要小心,因为在使用共享锁表实现您自己的同步逻辑的解决方案中,您始终存在并发问题,即两个集群节点同时从表中读取/写入。
最好是在一个db事务中执行以下步骤: - 读取共享锁表中的值 - 如果没有其他节点有锁,请锁定 - 更新表格,表明你采取了锁定
答案 3 :(得分:3)
我通过将其中一个框作为主文件解决了这个问题。 基本上在其中一个框上设置一个环境变量,如master = true。
并通过system.getenv(“master”)在java代码中读取它。 如果它的存在及其真实然后运行你的代码。
基本代码段
@schedule()
void process(){
boolean master=Boolean.parseBoolean(system.getenv("master"));
if(master)
{
//your logic
}
}
答案 4 :(得分:0)
您可以尝试使用WebLogic中的TimerManager(集群环境中的Job Scheduler)作为TaskScheduler实现(TimerManagerTaskScheduler)。它应该在集群环境中工作。
安德烈
答案 5 :(得分:0)
我最近实现了一个简单的注释库dlock,以仅在多个节点上执行一次计划任务。您只需执行以下操作即可。
@Scheduled(cron = "59 59 8 * * *" /* Every day at 8:59:59am */)
@TryLock(name = "emailLock", owner = NODE_NAME, lockFor = TEN_MINUTE)
public void sendEmails() {
List<Email> emails = emailDAO.getEmails();
emails.forEach(email -> sendEmail(email));
}
有关使用它的信息,请参见我的blog post。
答案 6 :(得分:0)
您不需要使用数据库来同步作业的开始。 在Weblogic应用程序上,您可以获得运行该应用程序的实例名称:
String serverName = System.getProperty("weblogic.Name");
只需将条件两个执行作业即可:
if (serverName.equals(".....")) {
execute my job;
}
如果要将作业从一台计算机退回另一台计算机,则可以获得一年中的当前日期;如果很奇怪,则在一台计算机上执行;如果是奇数,则可以在另一台计算机上执行该作业。 。 这样,您每天就可以加载另一台计算机。
答案 7 :(得分:-1)
我们可以通过使用以下cron字符串使集群上的其他计算机不运行批处理作业。它不会运行到2099年。
0 0 0 1 1? 2099