用途:该技能面向 Spring Boot 中 @Scheduled 定时任务的创建与审查,帮助处理调度表达式、时区、任务重叠、多实例部署等常见问题。资料明确其不覆盖 Spring Batch 的 chunk 与 restart 场景。
基线要求:以 Spring Boot 3 为基线,使用 Framework 6 的调度 API 和项目 Boot BOM,模板使用 Java 17。响应式定时方法和虚拟线程调度需要 Framework 6.1+/Boot 3.2+ 基线,不应把这些特性复制到更早的 Boot 3 应用中。
触发契约:在选择实现前,先明确调度时间、时区、最长运行时长、错过触发时的行为以及副本数量。调度只需启用一次。Spring cron 为六字段并包含秒;应显式指定时区,而非依赖部署主机默认值;当业务约定使用本地时间时,需测试夏令时切换。
执行方式区别:fixed delay 从任务完成时开始计时,fixed rate 按启动时间节奏执行,两者都不是集群级锁。加 @Async 会使任务完成与调度调用解耦,可能产生重叠执行;多个调度声明或 bean 实例也可能导致重复执行,不应为了掩盖慢任务而随意改动既有节奏。
模板与配置:StaleOrderSchedule 是一个轻量、默认禁用的 cron 适配器,需要提供 Clock 和 SweepAction bean,并在配置中启用 @EnableScheduling。良好配置需要显式 cron 才会启用;反面示例会产生不受追踪的重复工作。
副本与持久化:每个应用实例都可能注册触发器,需明确是所有副本都可工作、仅一个 leader 触发,还是各 worker 领取互不重叠的持久化条目。应复用已有协调机制(如集群调度器或经过测试的租约库),不要自行用 JVM 布尔锁或缺少所有权、过期和过期持有者处理的 Redis SETNX。租约可能在原 worker 仍在运行时过期,因此副作用要幂等,必要时由受保护资源做 fencing 校验;锁本身并不保证恰好一次。强制任务应持久化进度和重试意图,进程内调度不会在停机后重放错过的触发。
代码结构:调度适配器应保持精简,由独立服务领取有界批次并落实租户边界与事务规则;避免对无界扫描或远程调用使用单个事务。外部结果不确定时,用提供方幂等或对账处理。模板中的 SweepAction 是应用集成点,不是已实现的锁或队列。
运维与验证:设置运行时和 I/O 上限,用有界指标标签观察最后成功完成时间、耗时、失败和积压时长。记录异常不等于重试或告警策略。使用项目的调度器关闭策略和部署宽限期;中断不会自动回滚远程副作用;虚拟线程仍需下游限流;SimpleAsyncTaskScheduler 上的 fixed-delay 任务共享其调度线程。测试时可直接解析 cron 并验证禁用配置,无需等待实际时间;时间相关逻辑注入 Clock;使用协调机制时,补充竞争副本、租约过期、部分失败和重启的集成测试。附带测试夹具只检查适配器和触发器注册,不实现分布式调度。
常见误区:使用五字段 Unix cron 而漏掉 Spring 的秒字段;假定 @Scheduled 在多副本上只执行一次;用 @Async 解决慢定时任务而不限制和测试重叠;依赖租约保证恰好一次;静默启用破坏性维护任务;用长时间 sleep 测试时序。
官方参考:Boot 3 调度、Framework 6 任务调度、Scheduled 注解与禁用 cron。