ShedLock:定时任务共用同一锁ID的执行逻辑及优化方案
问题解答
1. 凌晨1点时任务的执行行为
当runEveryMinute成功获取锁时,runOnceEveryNight会直接跳过本次执行,不会进入等待队列。这是ShedLock的默认行为:任务尝试获取锁失败时,不会阻塞等待,而是直接放弃当前周期的执行。
2. 针对需求的更优配置方案
你的核心需求是:允许runEveryMinute每晚跳过一次,但runOnceEveryNight必须执行(不能等待24小时重试),以下是几种可行方案:
方案1:给夜间任务添加锁等待时间
修改runOnceEveryNight的@SchedulerLock注解,增加waitForLock参数,让它在获取锁失败时等待一段时间,直到runEveryMinute的锁释放:
@Scheduled(cron = "0 0 1 * * *") @SchedulerLock( name = "sameShedLockId", lockAtLeastFor = "PT10M", lockAtMostFor = "PT15M", waitForLock = "PT1M" // 最多等待1分钟获取锁 ) public void runOnceEveryNight() { // ... 原有业务逻辑 }
runEveryMinute的锁会在59秒后释放,runOnceEveryNight能在等待期内拿到锁执行;而runEveryMinute会因为锁被抢占跳过一次执行,完全符合你的需求。
方案2:调整分钟任务的定时规则,避开冲突时段
修改runEveryMinute的定时表达式,直接跳过凌晨1点整的执行,从根源上避免冲突:
// 每天0点-0点59分、2点-23点的每分钟第0秒执行,跳过1点整的时刻 @Scheduled(cron = "0 * 0,2-23 * * *") @SchedulerLock(name = "sameShedLockId", lockAtLeastFor = "PT59S", lockAtMostFor = "PT59S") public void runEveryMinute() { // ... 原有业务逻辑 }
方案3:在分钟任务中通过逻辑主动避开冲突
在runEveryMinute的方法内判断当前时间,若为凌晨1点整则直接返回,不执行业务逻辑:
@Scheduled("0 * * * * *") @SchedulerLock(name = "sameShedLockId", lockAtLeastFor = "PT59S", lockAtMostFor = "PT59S") public void runEveryMinute() { LocalTime now = LocalTime.now(); // 凌晨1点整直接跳过执行 if (now.equals(LocalTime.of(1, 0))) { return; } // ... 原有业务逻辑 }
内容的提问来源于stack exchange,提问作者Michiel
相关产品推荐
相关产品推荐

