# tiny-job **Repository Path**: leisureLXY/tiny-job ## Basic Information - **Project Name**: tiny-job - **Description**: 一个基于SpringBoot+Quartz开发的轻量级分布式任务调度管理系统 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 17 - **Forks**: 6 - **Created**: 2023-06-13 - **Last Updated**: 2026-10-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: 任务调度, 定时器, 分布式, quartz, SpringBoot ## README # Tiny Job # 轻量级分布式定时任务调度系统 ![SpringBoot](https://img.shields.io/badge/springboot-2.6.11-green.svg?style=flat-square) star fork > 一个基于SpringBoot+Quartz的的轻量级分布式定时任务调度系统 ## 主要技术选型 1、后端: - SpringBoot 2.7.18 - Quartz 2.3.2 - Mybatis-Plus 3.5.7 - Httpclient 4.5.13 2、前端: - Layui 2.8.11 - jQuery 2.1.4 ## 运行环境 - Jdk8 - MySQL5.6+ ## 运行启动教程 1. 新建`MySQL`数据库并导入`sql`文件夹下的数据库脚本 2. 修改配置文件中`application.yml`中数据库连接信息 3. 运行启动类`TinyJobApplication`,即可正常启动项目 4. 管理后台登录地址:`http://localhost:9009` 账户密码 `admin / 123456` ## 功能特色 ### 1. 项目维度管理:任务与主机的结构化归类 - 引入「项目」核心概念,将分散的主机信息、定时任务按业务场景或团队归属进行分组管理,避免资源混乱 - 支持项目级别的权限隔离(后续规划),为不同团队或业务线提供独立的任务调度空间,数据边界清晰 ### 2. 主机管理:灵活可控的执行器集群配置 - 支持单主机多地址维护(如 `http://172.89.56.117:8899`、`http://172.89.56.118:8899`),轻松构建执行器集群 - 集成安全调用策略(待完善),通过签名校验等机制保障任务请求的合法性,防止未授权调用 - 提供 **7种路由负载均衡策略**,并预留标准化扩展接口,满足不同场景下的任务分发需求: - FIRST(固定首地址):始终选择集群中第一个可用主机 - LAST(固定尾地址):始终选择集群中最后一个可用主机 - ROUND(轮询):按顺序循环分配任务,确保各主机负载均衡 - RANDOM(随机):随机选择可用主机,适用于无明显负载差异的场景 - LFU(最不经常使用):优先分配任务给调用频率最低的主机,优化资源利用率 - LRU(最近最久未使用):优先分配任务给长时间未调用的主机,避免单点过载 - CONSISTENT_HASH(一致性哈希):基于哈希算法固定任务与主机的映射关系,减少任务漂移 ### 3. 任务管理:可视化、高灵活的调度配置 - 全在线操作:支持任务的新增、编辑、删除、手动触发执行,以及实时启停 - 多触发器类型:同时支持 **CRON表达式**(复杂时间规则,如“每周一凌晨3点”)和 **SIMPLE触发器**(固定秒数间隔,如“每5秒执行一次”) - 丰富的任务参数配置: - 请求层:任务统一以 `POST JSON` 提交到执行器的框架入口,只需配置请求参数(JSON格式)与请求头(JSON格式),请求方式与请求地址由服务端统一维护 - 调度层: - **调度过期处理规则**:针对“任务触发时因系统故障/主机离线导致未执行”的场景,提供3种处理策略: - 立即执行:补执行所有错过的未执行任务(如系统宕机1小时,重启后一次性执行这1小时内所有应触发的任务),适用于“数据同步类”需补全数据的场景; - 执行一次:仅补执行1次最近错过的任务,且从当前时间重新计算下次触发时间(如每10分钟执行1次,宕机30分钟后重启,仅执行1次,下次按重启时间+10分钟触发),适用于“通知类”避免重复推送的场景; - 放弃执行(默认):忽略所有错过的未执行任务,直接从当前时间开始计算下次触发时间(如每小时执行1次,宕机2小时后重启,下次按重启时间+1小时触发),适用于“实时性要求低”无需补执行的场景; - **并发执行控制**:支持两种执行模式,适配不同任务特性: - 允许并发:同一任务的前一次执行未结束时,若到达下一次触发时间,直接启动新的执行进程(如任务执行耗时15秒,触发间隔10秒,会同时存在2个执行进程),适用于“无状态、可并行”的任务(如多节点数据独立查询); - 禁止并发(单机串行):同一任务的前一次执行未结束时,阻塞下一次触发(需等前一次执行完成后,再判断是否触发下一次任务),避免因并发导致的数据冲突(如任务操作同一数据库表,并发执行可能引发锁表/数据不一致); - 内置CRON表达式生成器:可视化配置时间规则,无需手动编写复杂表达式,降低使用门槛 ### 4. 任务执行日志:安全可追溯的调度记录 - 完整记录任务执行信息:包括执行时间、执行主机、请求参数、响应结果、执行状态(成功/失败)、耗时等,问题排查更高效 - 日志安全保护:采用国密SM3算法对日志内容进行签名,确保日志未被篡改,满足数据完整性校验需求 ### 5. 预警配置:任务异常的及时感知 - 支持预警邮箱配置,当任务执行失败(如请求超时、返回错误码)时,系统自动发送告警邮件,及时通知运维人员处理,减少故障影响范围 ### 6. 执行器统一入口:由框架拥有任务入口 - 任务只有一种调度方式:调度中心统一调用执行器的框架入口 `/tiny-job/executor/run`,再由执行器分发到业务注册的处理器 - 业务侧无需把接口暴露给调度中心,只需在Spring Bean的方法上标注 `@TinyJob("处理器名称")`,应用启动时自动扫描注册(处理器名称重复、方法签名不支持会在启动阶段直接报错) - 执行器入口属于框架自有路径,因此安全校验由框架强制完成,不存在「忘记配置导致接口裸奔」的问题 - 任务上下文随请求下发:业务可通过方法入参 `JobContext` 获取 `jobId`、`jobLogId`、任务名称、任务参数,也可通过 `JobSubjectHolder.getJobSubject()` 获取当前调度信息 **接入示例(三步)** 1)引入 `tiny-job-client` 依赖,并在配置文件中配置执行器(配置了 `worker-name` 即启用执行器): ```yaml tiny-job: admin-addresses: http://127.0.0.1:9009 # 调度中心地址,多个用逗号分隔,为空则关闭自动注册 project-id: 1 # 执行器所属项目ID worker-name: your-app-name # 执行器标识,需与调度中心主机配置一致 access-token: your-access-token # 开启安全调用时必填 ``` 2)编写任务处理器(必须是Spring Bean,方法签名仅支持 `无参` 或 `仅接收一个JobContext`): ```java @Component public class OrderJobHandler { @TinyJob(value = "orderSyncHandler", desc = "订单同步") public HandlerResult orderSync(JobContext context) { // context.getJobId() / context.getJobLogId() / context.getJobParam() return HandlerResult.success(); } } ``` > 返回值支持 `HandlerResult`(推荐)、`void` 及其他任意类型(非 HandlerResult 的返回值会被包装为成功结果,返回值内容作为执行信息回传调度中心) 3)在调度中心「任务管理」中新增任务:填写**处理器名称** `orderSyncHandler`,再按需配置触发器与调度规则即可,请求方式与请求地址由服务端统一维护。 ## 平台功能界面展示 首页 ![首页](tiny-job-admin/src/main/resources/static/images/readme/首页.png) 项目管理 ![项目管理](tiny-job-admin/src/main/resources/static/images/readme/项目管理.png) 项目管理-编辑 ![项目管理-编辑](tiny-job-admin/src/main/resources/static/images/readme/项目管理-编辑.png) 主机管理 ![主机管理](tiny-job-admin/src/main/resources/static/images/readme/主机管理.png) 主机管理-编辑 ![主机管理-编辑](tiny-job-admin/src/main/resources/static/images/readme/主机管理-编辑.png) 任务管理 ![任务管理](tiny-job-admin/src/main/resources/static/images/readme/任务管理.png) 任务管理-编辑 ![项目管理-编辑](tiny-job-admin/src/main/resources/static/images/readme/任务管理-编辑.png) 任务日志 ![任务日志](tiny-job-admin/src/main/resources/static/images/readme/任务日志.png) CRON生成 ![CRON生成](tiny-job-admin/src/main/resources/static/images/readme/CRON生成.png) ## 执行器主机安全策略配置 安全调用由「主机」维度的 `security_flag` + `access_token` 控制。调度中心侧开启安全调用后,调用时会自动带上 `nonce`、`timestamp`、`signature` 三个请求头(HmacSHA256 签名,签名有效期 60 秒)。**两个方向共用同一把 `accessToken`**:调度中心下发任务时用它签名,执行器注册/心跳/注销时也用它签名,调度中心再用主机记录里的同一个令牌验签——因此两侧校验走的是同一份实现,规则不会分叉。 任务统一走框架自有入口 `/tiny-job/executor/run`,**安全校验由执行器内部强制完成**(该路径与业务接口路径无关,且不受 `server.servlet.context-path` 影响),无需任何额外配置或拦截器。接入方只需在配置中填写与调度中心主机一致的 `tiny-job.access-token` 即可。 - 未配置 `access-token` 时入口会跳过校验并打印告警日志,便于本地联调 - 校验失败时执行器返回 `{"code":"413"}`,调度中心会把该次执行记为失败 - **生产环境必须为每个主机启用安全调用**:调度中心侧默认开启强制校验(`tiny-job.security.require-signature: true`),未配置 `accessToken` 的主机将被拒绝注册/心跳/注销(返回错误码 `9006`)。在后台开启「安全调用」时会自动生成 32 位令牌,把它复制到执行器的 `tiny-job.access-token` 即可。仅本地联调可临时把该开关设为 `false` - 判据以**令牌**为准(不看 `security_flag` 开关):主机一旦配置了 `accessToken`,进出两个方向的请求都必须带合法签名,不存在"把开关关掉即免验签"的绕过 ## 调度中心运维配置(`tiny-job.*`) 调度中心自身的运维项都收敛在 `application.yml` 的 `tiny-job` 下,默认值即生产可用值: | 配置项 | 默认值 | 说明 | | --- | --- | --- | | `tiny-job.security.require-signature` | `true` | 强制安全调用,未配置 `accessToken` 的执行器拒绝注册/心跳/注销 | | `tiny-job.log.running-grace-seconds` | `60` | **RUNNING 悬挂兜底**的宽限期:日志超过「该任务自身 `executor_timeout` + 宽限期」仍停在"运行中",即判定为调度中心异常中断(被 kill/宕机),自动置为失败并告警。阈值按任务超时时间计算,不会误判合法的长耗时任务 | | `tiny-job.log.stale-scan-limit` | `500` | 单轮悬挂扫描最多处理的日志条数 | | `tiny-job.log.retention-days` | `0` | 日志保留天数,**0 = 不清理**(审计数据不做静默删除)。设为 30 即开启,每天 03:30 分批清理更早的日志 | | `tiny-job.log.cleanup-batch-size` | `2000` | 每批删除行数,分批删除避免长事务与锁等待 | | `tiny-job.alarm.suppress-minutes` | `10` | 同一任务的失败告警抑制窗口:窗口内只发一条,避免任务持续失败刷爆邮箱(0 = 不抑制)。发信用独立线程池 `mail-alarm-*`,与主机健康探测互不影响 | > 已建库的环境请额外执行 `sql/upgrade-log-performance.sql` 给 `t_job_log` 补索引(日志列表、首页趋势、悬挂扫描与清理都依赖它);全新部署直接导入 `sql/tiny-job.sql` 即可。 # 项目计划 | 功能模块 | 状态 | 说明 | |------------|------------|---------------------------------------------------------------------------------------| | 分布式调度器核心功能 | ✅ 已完成 | 基于Quartz实现 | | 项目管理 | ✅ 已完成 | 实现项目的创建、编辑、删除,以及任务/主机与项目的关联 | | 接口管理 | ✅ 已完成 | 管理任务关联的接口信息,支持接口参数、请求方式等配置 | | 接口修改历史 | ✅ 已完成 | 记录接口配置的修改日志,支持回溯历史版本,便于问题定位 | | 接口访问日志 | ✅ 已完成 | 记录接口的调用记录,包括调用时间、调用者、请求参数、响应结果等 | | 首页大屏 | ✅ 已完成 | 可视化展示下的任务执行概况、主机状态、异常统计等核心数据 | | 数据统计页面 | ✅ 已完成 | 提供任务执行成功率、主机负载、接口调用量等统计图表,辅助运营决策 | | 项目成员协作功能 | ✅ 已完成 | 支持多成员协作管理同一项目,实现权限共享(基础版) | | 项目导出/导入 | ✅ 已完成 | 支持项目级数据的备份(导出)与恢复(导入),便于环境迁移或数据备份 | | 自定义头像修改 | ✅ 已完成 | 支持/用户自定义头像,提升系统个性化体验 | | 接口分模块管理 | 📅️ 待完成 | 支持接口按业务模块分组管理,适用于接口数量较多的复杂项目 | | 主机节点监控与上下线 | ✅ 已完成 | 内置定时监控任务,主动检测主机存活状态,实现故障节点自动下线、恢复后上线 | | 角色与权限管理 | 📅 待完成 | 区分管理员、操作员等角色,支持按项目维度分配权限(如“仅查看任务”“可编辑任务”) | | 任务失败告警增强 | 📅 待完成 | 增加webhook告警(如企业微信机器人、钉钉机器人、自建告警平台),支持自定义告警URL、请求体格式 | | 任务回调功能 | 📅 待完成 | 添加任务执行成功/失败回调功能,任务结束后回调到任务中心[JobClient.handleSuccess(msg),JobClient.handleFail(msg) ] | | 主机自动注册 | 📅 待完成 | 通过继承 tinyjob-client 来实现主机自动注册功能 | | 广播任务 | 📅 待完成 | | ## 常用cron表达式示例 - 0/2 * * * * ? 表示每2秒 执行任务 - 0 0/2 * * * ? 表示每2分钟 执行任务 - 0 0 2 1 * ? 表示在每月的1日的凌晨2点调整任务 - 0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业 - 0 15 10 ? 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午10:15执行作 - 0 0 10,14,16 * * ? 每天上午10点,下午2点,4点 - 0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时 - 0 0 12 ? * WED 表示每个星期三中午12点 - 0 0 12 * * ? 每天中午12点触发 - 0 15 10 ? * * 每天上午10:15触发 - 0 15 10 * * ? 每天上午10:15触发 - 0 15 10 * * ? 每天上午10:15触发 - 0 15 10 * * ? 2005 2005年的每天上午10:15触发 - 0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发 - 0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发 - 0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 - 0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发 - 0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发 - 0 15 10 ? * MON-FRI 周一至周五的上午10:15触发 - 0 15 10 15 * ? 每月15日上午10:15触发 - 0 15 10 L * ? 每月最后一日的上午10:15触发 - 0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发 - 0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发 - 0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发