Scheduler Starter
受众:开发者 摘要:统一任务调度 Facade。db-scheduler / spring-scheduled / redis / memory 多种 provider,执行日志、暂停恢复、手动触发、Cron 校验、失败重试、后台运维入口。
何时使用
| 场景 | 建议 |
|---|---|
| 一次性延迟任务(订单超时关闭、限时优惠) | Scheduler.once(taskName, instanceId, fireAt) |
| 固定间隔周期任务(每 5 分钟同步) | Scheduler.fixedDelay(taskName, instanceId, interval) |
| Cron 表达式任务(每日 02:00) | Scheduler.cron(taskName, instanceId, "0 0 2 * * *") |
| 多实例可靠任务 | 默认 db-scheduler provider |
| 轻量延迟 / 补偿任务(已有 Redis) | 切到 redis provider |
| 单元测试 / 单进程诊断 / lite 兼容模式 | 切到 spring-scheduled provider |
不要把高频毫秒级任务塞进来(用 Quartz 或专门方案);不要把业务事件同步处理塞进来(用 Event Facade)。
快速开始
spring:
open:
scheduler:
default-provider: db-scheduler@Component
public class OrderTimeoutCloseTask implements SchedulerTask {
@Override
public String name() {
return "order.timeout.close";
}
@Override
public String description() {
return "订单超时未支付时自动关闭订单";
}
@Override
public void execute(SchedulerTaskContext context) {
// 业务 Service 调用
}
}Scheduler.once("order.timeout.close", "order-10001",
Instant.now().plus(Duration.ofMinutes(30)));SchedulerTask 注册为 Spring Bean 后自动进入任务注册表。description() 是可选说明,默认留空;它只用于后台任务列表帮助运维识别任务用途,不会写入 scheduled_tasks 这类 provider 执行状态表。
Facade API
// 一次性延迟任务
Scheduler.once(taskName, instanceId, fireAt);
// 固定间隔
Scheduler.fixedDelay(taskName, instanceId, interval);
Scheduler.fixedDelay(taskName, instanceId, initialDelay, interval);
// Cron 表达式
Scheduler.cron(taskName, instanceId, cron);
// 暂停 / 恢复(运行时控制)
Scheduler.pause();
Scheduler.resume();
// 手动触发 / 取消单个实例
Scheduler.trigger(taskName, instanceId);
Scheduler.cancel(taskName, instanceId);taskName 必须与 SchedulerTask.name() 一致。instanceId 区分同一任务的不同实例(订单号、交易号、业务 ID)。
源码机制骨架
Scheduler starter 的运行链路按 Facade、Manager、Registry、Provider、Execution Log 分层:
Scheduler是业务侧 Facade。静态方法只取当前 Spring 容器绑定的SchedulerManager,不直接读取配置、不直接触碰 db-scheduler / Redis / TaskScheduler。SchedulerManagerProvider在自动配置完成后把SchedulerManager绑定到 Facade;测试或上下文销毁时负责清理绑定。DefaultSchedulerManager负责校验SchedulerTask是否已注册,并按spring.open.scheduler.default-provider选择 provider;单次调度不覆盖 provider,便于环境级统一切换调度后端。DefaultSchedulerTaskRegistry收集所有 Spring Bean 形式的SchedulerTask,按SchedulerTask.name()建立索引;重复名称会在注册期失败。任务可选的description()会作为注册元数据提供给后台运维视图。ScheduleRequest是 provider 共享的标准请求模型,统一承载 once / fixedDelay / cron 三类调度请求,并补齐空 instanceId、默认时区和一次性任务默认触发时间。ScheduledTask是提交快照,只表示任务已交给 provider;是否执行成功以执行日志和 provider 状态为准。SchedulerTaskContext是业务任务执行时看到的调度事实,包含任务名、实例 ID、调度类型、计划时间、实际执行时间、provider 和 traceId。SpringScheduledSchedulerProvider基于 SpringTaskScheduler执行动态调度任务,适合单实例和 lite 模式;它不是静态@Scheduled注解扫描器,也不提供任务持久化或多实例协调。MemorySchedulerProvider直接用 SpringTaskScheduler触发任务,不持久化任务实例,主要用于本地测试和极简单实例场景。DbSchedulerProvider把请求转换为 db-scheduler 的 one-time / recurring task instance;DbSchedulerTaskDispatcher在触发时再按 taskName 找到业务SchedulerTask并记录执行日志。RedisSchedulerProvider用 Hash 保存任务元数据、ZSet 保存到期索引、短期锁避免多实例重复执行;失败后按 retry 配置重排一次性任务,重复任务按下一次计划继续调度。SchedulerExecutionRecorder是所有 provider 执行任务前后的统一包裹层,负责 traceId 绑定、开始 / 完成日志和异常透传。JdbcSchedulerExecutionLogStore写入scheduled_task_execution_log;表名只允许配置为数据库标识符,具体值使用参数绑定。SchedulerExecutionLogCleanupRegistrar把执行日志清理注册成一个普通 Cron 调度任务,因此清理逻辑同样走当前默认 provider。spring-open-core-scheduler汇总 provider 状态、任务指标、misfire 策略、Cron 校验、最近执行日志和运行时操作入口;Scheduler starter 本身只保留调度 contract。
配置项
spring:
open:
scheduler:
enabled: true # 启用开关
default-provider: db-scheduler # 默认 provider
providers:
spring-scheduled:
provider: spring-scheduled
pool-size: 4
thread-name-prefix: spring-open-scheduled-
db-scheduler:
provider: db-scheduler
one-time-task-name: spring-open-scheduler-once
recurring-task-name: spring-open-scheduler-recurring
retry:
max-retries: 0 # 0 = 不限次数
interval: 5m
redis:
provider: redis
enabled: true
auto-startup: false
key-prefix: scheduler:redis
scan-interval: 1s
batch-size: 50
lock-ttl: 5m
memory:
provider: memory
pool-size: 4
execution-log:
enabled: true
table-name: scheduled_task_execution_log
cleanup:
enabled: true
retention: 30d
cron: "0 0 3 * * *"| 配置 | 默认值 | 说明 |
|---|---|---|
enabled | true | 关闭后整个 AutoConfiguration 跳过 |
default-provider | db-scheduler | 默认调度后端 |
providers.<name>.provider | - | 真实 provider |
execution-log.enabled | true | 是否写执行日志 |
execution-log.cleanup.retention | 30d | 日志保留天数 |
execution-log.cleanup.cron | 0 0 3 * * * | 清理任务 Cron |
开发期不保留旧配置兼容;Scheduler 统一使用 default-provider / providers.*。
Provider 扩展
| Provider 配置 | Provider | 说明 | 适用 |
|---|---|---|---|
db-scheduler | db-scheduler | 基于数据库持久化调度 | 默认,多实例、可靠任务 |
spring-scheduled | spring-scheduled | 基于 Spring TaskScheduler 的动态本地调度 | 单实例诊断、lite 兼容模式 |
redis | redis | Redis ZSet 轻量延迟调度 | 轻量补偿、短延迟 |
memory | memory | 本机内存 | 测试、极简单实例 |
lite 兼容模式自动切换为 spring-scheduled;普通开发不推荐用 lite 绕开默认调度基础设施。
scheduled_tasks.task_data 是 db-scheduler 内部序列化任务数据,MySQL/MariaDB 用 blob,PostgreSQL 用 bytea,不要改成 text。
执行日志
调度执行日志默认写入 scheduled_task_execution_log,记录:
- 任务开始时间、成功 / 失败、耗时
- TraceId 链路追踪
- 错误摘要
自动清理任务默认每天 03:00 清理 30 天前日志。
后台任务概览会展示最近执行日志入口和最近 7 天执行趋势。执行趋势直接从执行日志聚合出每日执行数、成功数、失败数、运行中数和平均耗时,便于先判断任务是否出现波动;执行日志仍是“任务执行事实”,不替代业务审计或业务状态表,业务补偿、账务、审批等长期事实应留在各自业务模块。
后台运维 API
spring-open-core-scheduler 提供调度运维入口(权限:scheduler:*):
| API | 说明 |
|---|---|
GET /api/v1/admin/scheduler/status | 调度状态 |
GET /api/v1/admin/scheduler/operations | 调度运维快照、能力清单和 runbook 提示 |
GET /api/v1/admin/scheduler/tasks | 任务列表(关键字 / 状态 / 失败筛选 / 排序) |
GET /api/v1/admin/scheduler/tasks/failures | 失败任务聚合 |
GET /api/v1/admin/scheduler/tasks/{taskName}/metrics | 单任务指标(成功率 / 失败率 / 平均耗时) |
POST /api/v1/admin/scheduler/cron/validate | Cron 表达式校验并预览后续触发时间 |
POST /api/v1/admin/scheduler/pause | 暂停调度 |
POST /api/v1/admin/scheduler/resume | 恢复调度 |
POST /api/v1/admin/scheduler/tasks/{taskName}/instances/{instanceId}/trigger | 手动触发 |
POST /api/v1/admin/scheduler/tasks/{taskName}/instances/{instanceId}/stop | 停止任务实例(运维语义,底层复用取消能力) |
DELETE /api/v1/admin/scheduler/tasks/{taskName}/instances/{instanceId} | 取消任务 |
GET /api/v1/admin/scheduler/execution-logs | 执行日志分页 |
GET /api/v1/admin/scheduler/execution-logs/trends | 执行日志每日趋势(默认最近 7 天,最长 90 天) |
POST /api/v1/admin/scheduler/execution-logs/{id}/retry | 基于失败日志重试(仅 FAILED 状态) |
POST /api/v1/admin/scheduler/execution-logs/cleanup | 清理旧日志 |
后台页面在有副作用的暂停、恢复、手动触发和停止操作前会做二次确认。任务列表会在任务名下展示可选 description,便于区分业务用途;列表里的 misfirePolicy 是 provider 暴露的执行策略摘要,当前 provider 未提供细分策略时显示 provider-default。
GET /api/v1/admin/scheduler/operations 是只读运维快照,汇总默认 provider、暂停状态、注册任务数、失败任务数、运行中执行数、执行日志可用性、成功率、平均耗时、能力清单和 runbook 提示。它不会暂停、恢复、触发或停止任何任务,适合发布前 smoke、故障排查和确认业务任务是否已经被 Scheduler 注册表发现。若快照提示没有注册任务,应优先检查 SchedulerTask Bean 是否被扫描,以及业务 registrar 是否在运行期成功调用 SchedulerManager。
扩展边界
- 新增底层调度介质时实现
SchedulerProvider,并在自动配置中注册 provider Bean;业务代码仍只依赖Scheduler/SchedulerTask/SchedulerManager。 - 新增业务任务时实现
SchedulerTask,任务名保持应用内唯一,业务参数通过instanceId指向业务对象,不在调度数据里塞 Entity、连接、文件句柄或临时上下文。 ScheduleRequest只承载调度事实,不承载业务审批、订单状态、工作流节点或权限判断。MemorySchedulerProvider不做持久化,不能作为多实例可靠调度;生产多实例优先db-scheduler。RedisSchedulerProvider适合轻量延迟和补偿,不作为长期事实数据源;复杂死信、批量恢复、跨区域灾备仍应走专用队列 / 调度方案。- 执行日志只记录任务执行事实和错误摘要,不替代业务审计、账务流水、幂等表或操作日志。
spring-open-core-scheduler负责后台运维 API 和执行日志持久化运维入口;Scheduler starter 只提供底层调度 contract,不反向依赖运行时底座模块。
注意事项
- 多实例部署优先
db-scheduler - 生产修改 Cron 前先使用后台 Cron 校验预览触发时间,再保存业务配置或重新注册任务
- Redis provider 适合轻量延迟任务,不作为长期事实数据源
- 失败任务通过执行日志 + 手动重试入口处理,不在业务任务中重复实现
- 应用启动期 db-scheduler 配置
always-persist-timestamp-in-utc=true避免 MySQL TIMESTAMP 跨时区偏差 - Scheduler starter 自身不依赖 MyBatis-Plus;只有
spring-open-core-scheduler存在时才使用 MyBatis-Plus 执行日志 store
验证命令
./mvnw -pl spring-open-starters/spring-open-starter-scheduler -am test -DskipITs
# 真实基础设施集成测试(MySQL + PostgreSQL + Redis Testcontainers)
./mvnw -pl spring-open-starters/spring-open-starter-scheduler -am verify -DskipITs=false相关
- Queue(异步任务投递):queue.md
- Event(同步 / 异步事件):event.md
- Pipeline(责任链编排):pipeline.md
- 后台页面与运维入口:view-admin.md
- Provider 扩展模型:provider.md