scaffold-job 任务调度模块
模块概述
scaffold-job 基于 Quartz 核心思想实现的轻量级任务调度框架。采用 SPI 架构,业务模块只需实现 JobHandler 接口并使用 @JobHandler 注解注册,即可被调度引擎自动发现和执行。支持 Cron 表达式调度、手动触发、任务暂停/恢复、失败重试、分布式锁(依赖 Redis)等能力。
功能列表
- Cron 调度:支持标准 Cron 表达式,应用启动时自动加载所有正常状态的任务
- 手动触发:支持通过 API 立即触发任务执行
- 任务生命周期管理:创建、更新、删除、暂停、恢复
- 失败重试:可配置重试次数和重试间隔
- 分布式锁:非并发任务使用 Redis 分布式锁保证单节点执行
- 执行日志:完整记录每次执行的状态、耗时、执行主机、traceId
- 超时控制:可配置任务超时时间
核心组件
| 层 |
类名 |
职责 |
| Controller |
JobInfoController |
任务管理接口,路径 /v1/job/info |
| Controller |
JobLogController |
执行日志接口,路径 /v1/job/log |
| Service |
JobInfoService |
任务的增删改查、触发、暂停、恢复 |
| Service |
JobLogService |
执行日志的查询 |
| Core |
JobScheduler |
调度引擎,管理 Cron 注册/取消/生命周期 |
| Core |
JobExecutor |
任务执行器,负责锁获取、日志记录、重试、执行 |
| SPI |
JobHandler |
任务处理器接口,业务模块实现 |
| SPI |
JobContext |
执行上下文(任务ID、名称、参数、重试序号等) |
| SPI |
ExecuteResult |
执行结果(成功/失败、消息) |
| SPI |
JobHandlerRegistry |
处理器注册中心,自动扫描 @JobHandler 注解的 Bean |
| Annotation |
@JobHandler |
标注在处理器类上,声明处理器名称 |
| Entity |
JobInfo |
任务信息实体 |
| Entity |
JobLog |
执行日志实体 |
| Config |
JobAutoConfiguration |
自动配置类 |
| Config |
JobProperties |
配置属性类 |
| Config |
JobSchedulerConfig |
调度线程池配置 |
配置参数
配置前缀:scaffold.job
| 参数 |
类型 |
默认值 |
说明 |
enabled |
boolean |
true |
模块开关 |
poolSize |
Integer |
CPU核数 * 2 |
调度线程池大小 |
threadNamePrefix |
String |
job-scheduler- |
线程名前缀 |
枚举值说明
| 枚举 |
值 |
说明 |
JobStatusEnum.NORMAL |
0 |
正常(可调度执行) |
JobStatusEnum.PAUSED |
1 |
暂停 |
JobStatusEnum.DISABLED |
2 |
禁用 |
MisfirePolicyEnum.EXECUTE_NOW |
1 |
立即执行 |
MisfirePolicyEnum.EXECUTE_ONCE |
2 |
执行一次 |
MisfirePolicyEnum.IGNORE |
3 |
忽略 |
TriggerTypeEnum.CRON |
1 |
Cron 触发 |
TriggerTypeEnum.MANUAL |
2 |
手动触发 |
JobLogStatusEnum.RUNNING |
- |
执行中 |
JobLogStatusEnum.SUCCESS |
- |
成功 |
JobLogStatusEnum.FAILED |
- |
失败 |
注意:JobStatusEnum 和 JobLogStatusEnum 为多态状态机,不遵循布尔语义规范。
API 接口列表
任务管理 /v1/job/info
| 方法 |
路径 |
说明 |
| POST |
/create |
创建任务 |
| POST |
/update |
更新任务 |
| POST |
/delete/{id} |
删除任务 |
| GET |
/get/{id} |
任务详情 |
| GET |
/page |
任务分页查询 |
| POST |
/trigger/{id} |
手动触发任务执行 |
| POST |
/pause/{id} |
暂停任务 |
| POST |
/resume/{id} |
恢复任务 |
执行日志 /v1/job/log
| 方法 |
路径 |
说明 |
| GET |
/page |
执行日志分页查询 |
| GET |
/get/{id} |
执行日志详情 |
SPI 扩展点
JobHandler 接口
业务模块实现此接口,配合 @JobHandler 注解注册到调度引擎。
public interface JobHandler {
ExecuteResult execute(JobContext context);
}
JobContext 上下文字段
| 字段 |
类型 |
说明 |
jobId |
Long |
任务ID |
jobName |
String |
任务名称 |
params |
String |
任务参数 |
retryIndex |
int |
当前重试序号(0=首次执行) |
logId |
Long |
执行日志ID |
traceId |
String |
链路追踪ID |
ExecuteResult 工厂方法
| 方法 |
说明 |
ExecuteResult.success() |
返回成功结果 |
ExecuteResult.success(message) |
返回成功结果(含消息) |
ExecuteResult.failure(message) |
返回失败结果(含错误信息) |
使用示例
实现一个定时任务处理器
@Slf4j
@JobHandler("orderTimeoutChecker")
@Component
public class OrderTimeoutJobHandler implements JobHandler {
private final OrderRepository orderRepository;
@Override
public ExecuteResult execute(JobContext context) {
log.info("开始检查超时订单, params={}", context.getParams());
int count = orderRepository.cancelTimeoutOrders();
return ExecuteResult.success("取消超时订单 " + count + " 笔");
}
}
通过 API 创建定时任务
const { data } = await post('/v1/job/info/create', {
jobName: '超时订单检查',
handlerBean: 'orderTimeoutChecker',
cronExpression: '0 */5 * * * ?',
params: '{"timeoutMinutes": 30}',
retryCount: 2,
retryInterval: 10,
concurrent: 0, // 不允许并发
misfirePolicy: 1, // 立即执行
timeout: 300 // 超时 300 秒
})
手动触发和暂停任务
// 手动触发
await post(`/v1/job/info/trigger/${jobId}`)
// 暂停任务
await post(`/v1/job/info/pause/${jobId}`)
// 恢复任务
await post(`/v1/job/info/resume/${jobId}`)
注意事项
@JobHandler 注解的 value 值必须与 t_job_info 表的 handler_bean 字段一致。
- 应用启动时
JobScheduler 自动加载所有 status=0(正常)的任务并注册 Cron 调度。
- 非并发任务(
concurrent=0)使用 Redis 分布式锁,依赖 scaffold-redis 模块。
- 任务执行支持失败重试,重试次数和间隔在
JobInfo 中配置。
- 执行日志记录了执行主机、traceId,便于问题排查。
- 删除任务会同时取消其 Cron 调度。
- 模块启用条件:
scaffold.job.enabled=true(默认启用)。
- 状态枚举:
JobStatusEnum、JobLogStatusEnum 为多态状态机,不遵循布尔语义规范(status=0 表示正常,这与布尔语义规范不同,保留原有值)