Cron4jPlugin定时插件在多tomcat的负载均衡中会执行多次

gaopeng8 发布于 04/15 19:24
阅读 40
收藏 2

咨询下,用Cron4jPlugin定时配置定时任务,在多tomcat的负载均衡中会多次的执行,有没有其他方式来解决这个问题,只想执行一次?

加载中
0
JFinal
JFinal

利用数据库或者 redis 担当一个共享数据的地方,让多个 Cron4jPlugin 去共享数据库或共享的 redis 中去取要调度的任务

 

例如使用 mysql 数据库, 建一张 task 表, 其中有下面字段:

task(id, cron, class, lock)

其中 id 是任务 id,cron 是任务调度用的表达式,lock 是抢占该任务的锁,关键在于如何抢点锁,下面是示例代码:

public Task getTask() {
  // 获取一条未被抢占的 task 记录的 id 值
  Integer taskId = Db.queryId("select id from task where lock is null");
  
  // 所有 task 已被抢占
  if (taskId == null) {
     return null;
  }
  
  // 获取一个全球唯一的不可能重复的 uuid 值,作为本 JVM 进程抢占 task 的 lock 值
  String lock = StrKit.getRandomUUID();
  
  // 更新该 task 的 lock 值抢占该 task,注意 where 条件中的 lock is null 避免多个进程抢占同一个 task
  int n = Db.update("update task set lock = ? where id = ? and lock is null", lock, taskId);
  
  // n > 0 时表示抢占成功
  if (n > 0) {
     Task task = new Task().findById(taskId);

     // 只有 lock 更新成了自己生成的 lock 值,才能表明被自己抢到了
     if (task.getLock().equals(lock) {
       return task;
     }
  }

  return null;
}

   上面的 getTask 方法可能会返回 null,这是由于多进程/线程会有争抢的情况出现,可以使用在 for 循环中执行该 getTask() 方法重试抢几次的策略

   如果还觉得并发下不保险,可以在上面代码中添加事务:

Db.tx( () -> {
   这里放上前面 getTask 中的代码,抢占成功 return true, 否则 return false;
});

 

最后,通过 getTask() 得到 Task 对象以后,取出 Task 中的 cron 表达式以及 class 值来 new Cron4jPlugin(...).start()

JFinal
JFinal
回复 @gaopeng8 : 代码刚刚被改进过,上一次的少一个 if 判断: // 只有 lock 更新成了自己生成的 lock 值,才能表明被自己抢到了 if (task.getLock().equals(lock) { return task; } 注意再回看一下代码
gaopeng8
gaopeng8
回复真是太及时了,简直秒回,感谢波总,我试试。
返回顶部
顶部