Spring Cron调度任务配置每59秒间隔执行出现重复触发问题咨询
问题原因分析
你的问题确实出在Cron表达式的配置上,咱们先拆解下*/59 * 9-21 * * *这个表达式的含义:
Cron表达式的结构是 秒 分 时 日 月 周,其中秒位的*/59表示「在秒的取值范围(0-59)内,每隔59秒触发一次」。
那具体怎么计算触发时间呢?
- 第一个触发点是每分钟的
0秒(因为0是秒范围的起始值) - 下一个触发点是
0+59=59秒,刚好在当前分钟内 - 但Cron的调度逻辑是基于字段独立周期判断的,
*/59在秒位的本质是匹配所有满足秒数 % 59 == 0的时间点——0和59都符合这个条件(0%59=0,59%59=0),所以每分钟的0秒和59秒都会触发任务,这就是你日志里看到重复执行的核心原因。
更关键的是:Cron是基于固定时间点的调度,不管上一次任务是否执行完成,到了时间点就会触发,这和你想要的「以上一次任务结束时间为准,间隔59秒执行」的需求完全不匹配。
正确的解决方案
因为你的核心需求是「任务结束后间隔固定时间再执行」,同时限制在9-21点之间,Grails 4基于Spring框架,直接用@Scheduled的fixedDelay参数就能完美实现,不需要Cron表达式:
import org.springframework.scheduling.annotation.Scheduled; import java.time.LocalTime; // ... @Scheduled(fixedDelay = 59000) // 59000毫秒 = 59秒,上一次任务结束后间隔59秒执行 public void schedule() { LocalTime now = LocalTime.now(); // 判断当前时间是否在9:00-21:00之间 if (now.isBefore(LocalTime.of(9, 0)) || now.isAfter(LocalTime.of(21, 0))) { return; // 不在时间范围内,直接返回不执行任务逻辑 } try { log.info("Scheduler starts!"); } catch (Exception e) { log.error("Error was caught in scheduler", e); } }
这样配置后:
- 任务会在上一次执行结束后,等待59秒再启动下一次,完全符合你的「以上一次结束为准间隔59秒」的要求
- 通过代码判断当前时间,确保只有9-21点之间才会执行任务逻辑
- 不会出现Cron那种固定时间点重复触发的问题
如果你的任务执行时间可能超过59秒,fixedDelay依然会等任务结束后再开始计时,这比Cron的时间点调度更贴合你的需求。
内容的提问来源于stack exchange,提问作者SorryForAsking
相关产品推荐
相关产品推荐

