Docker 部署 XXL-Job 调度中心
概述
XXL-Job 是项目中使用的分布式任务调度平台,用于管理定时任务的注册、调度与监控。
项目中已集成的定时任务:
| 模块 | JobHandler | 说明 |
|---|---|---|
| HRM | punchRecordGenerateJob | 每日自动生成打卡记录 |
| HRM | employeeTransferByEffectiveDateJob | 员工调动生效处理 |
| HRM | employeeResignationByResignationDateJob | 员工离职生效处理 |
| CRM | customerAutoPutPoolJob | 客户自动回收公海 |
| Pay | payOrderSyncJob | 支付订单同步 |
| Pay | payOrderExpireJob | 支付订单过期 |
| Pay | payRefundSyncJob | 退款同步 |
| Pay | payNotifyJob | 支付通知 |
| Pay | payTransferSyncJob | 转账同步 |
| Trade | tradeOrderAutoCancelJob | 订单自动取消 |
| Trade | tradeOrderAutoReceiveJob | 订单自动收货 |
| Trade | tradeOrderAutoCommentJob | 订单自动评价 |
| Trade | brokerageRecordUnfreezeJob | 佣金解冻 |
| Promotion | couponExpireJob | 优惠券过期 |
| Promotion | combinationRecordExpireJob | 拼团过期 |
| Statistics | tradeStatisticsJob | 交易统计 |
| Statistics | productStatisticsJob | 商品统计 |
| Infra | accessLogCleanJob | 访问日志清理 |
| Infra | errorLogCleanJob | 错误日志清理 |
| IoT | deviceOfflineCheckJob | 设备离线检测 |
| IoT | deviceUpgradeJob | 设备 OTA 升级 |
| AI | aiMidjourneySyncJob | Midjourney 绘图同步 |
| AI | aiSunoSyncJob | Suno 音乐同步 |
| System | demoJob | 示例任务 |
项目配置信息:
| 配置项 | 值 |
|---|---|
| XXL-Job 版本 | 2.4.0 |
| Admin 地址 | http://127.0.0.1:9090/xxl-job-admin |
| 执行器 AppName | yudao-server |
| accessToken | default_token |
前置条件
- 服务器已安装 Docker
- MySQL 数据库已部署并可访问(项目中已有 MySQL,直接复用)
- 确保端口
9090未被占用
部署步骤
步骤 1:创建 XXL-Job 数据库
XXL-Job Admin 需要一个独立数据库 xxl_job 存储调度信息,不要使用业务库 ruoyi-office。
1.1 建库建表(推荐)
优先执行交付包中的脚本(已含建库、8 张表、默认执行器 yudao-server、管理员 admin/123456):
# 路径以工作区为准
mysql -h 127.0.0.1 -P 3306 -uroot -p < ruoyi-office-db/dump/latest/xxl_job_schema.sql再按版本注册业务定时任务:
# 全功能版
mysql -h 127.0.0.1 -P 3306 -uroot -p < ruoyi-office-db/dump/latest/xxl_job_init_all.sql
# OA 商业版(勿用 init_all)
mysql -h 127.0.0.1 -P 3306 -uroot -p < ruoyi-office-db/dump/latest/xxl_job_init_oa.sql
xxl_job_init_*.sql只有 INSERT,必须先跑xxl_job_schema.sql。完整说明见dump/latest/README.md。
1.1b 手工粘贴建表 SQL(备选)
若手头没有上述文件,可登录 MySQL 执行以下 SQL(与 xxl_job_schema.sql 等价主体):
-- 创建数据库
CREATE DATABASE IF NOT EXISTS `xxl_job` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE `xxl_job`;
-- xxl_job_info 任务信息表
CREATE TABLE `xxl_job_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`job_group` int(11) NOT NULL COMMENT '执行器主键ID',
`job_desc` varchar(255) NOT NULL,
`add_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
`author` varchar(64) DEFAULT NULL COMMENT '作者',
`alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮件',
`schedule_type` varchar(50) NOT NULL DEFAULT 'NONE' COMMENT '调度类型',
`schedule_conf` varchar(128) DEFAULT NULL COMMENT '调度配置,值含义取决于调度类型',
`misfire_strategy` varchar(50) NOT NULL DEFAULT 'DO_NOTHING' COMMENT '调度过期策略',
`executor_route_strategy` varchar(50) DEFAULT NULL COMMENT '执行器路由策略',
`executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',
`executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数',
`executor_block_strategy` varchar(50) DEFAULT NULL COMMENT '阻塞处理策略',
`executor_timeout` int(11) NOT NULL DEFAULT '0' COMMENT '任务执行超时时间,单位秒',
`executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失败重试次数',
`glue_type` varchar(50) NOT NULL COMMENT 'GLUE类型',
`glue_source` mediumtext COMMENT 'GLUE源代码',
`glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注',
`glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间',
`child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔',
`trigger_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '调度状态:0-停止,1-运行',
`trigger_last_time` bigint(13) NOT NULL DEFAULT '0' COMMENT '上次调度时间',
`trigger_next_time` bigint(13) NOT NULL DEFAULT '0' COMMENT '下次调度时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- xxl_job_log 任务调度日志表
CREATE TABLE `xxl_job_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`job_group` int(11) NOT NULL COMMENT '执行器主键ID',
`job_id` int(11) NOT NULL COMMENT '任务主键ID',
`executor_address` varchar(255) DEFAULT NULL COMMENT '执行器地址,本次执行的地址',
`executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',
`executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数',
`executor_sharding_param` varchar(20) DEFAULT NULL COMMENT '执行器任务分片参数,格式如 1/2',
`executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失败重试次数',
`trigger_time` datetime DEFAULT NULL COMMENT '调度-时间',
`trigger_code` int(11) NOT NULL COMMENT '调度-结果',
`trigger_msg` text COMMENT '调度-日志',
`handle_time` datetime DEFAULT NULL COMMENT '执行-时间',
`handle_code` int(11) NOT NULL COMMENT '执行-状态',
`handle_msg` text COMMENT '执行-日志',
`alarm_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '告警状态:0-默认、1-无需告警、2-告警成功、3-告警失败',
PRIMARY KEY (`id`),
KEY `I_trigger_time` (`trigger_time`),
KEY `I_handle_code` (`handle_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- xxl_job_log_report 任务调度日志报表
CREATE TABLE `xxl_job_log_report` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`trigger_day` datetime DEFAULT NULL COMMENT '调度-时间',
`running_count` int(11) NOT NULL DEFAULT '0' COMMENT '运行中-日志数量',
`suc_count` int(11) NOT NULL DEFAULT '0' COMMENT '执行成功-日志数量',
`fail_count` int(11) NOT NULL DEFAULT '0' COMMENT '执行失败-日志数量',
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `i_trigger_day` (`trigger_day`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- xxl_job_logglue GLUE日志表
CREATE TABLE `xxl_job_logglue` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`job_id` int(11) NOT NULL COMMENT '任务主键ID',
`glue_type` varchar(50) DEFAULT NULL COMMENT 'GLUE类型',
`glue_source` mediumtext COMMENT 'GLUE源代码',
`glue_remark` varchar(128) NOT NULL COMMENT 'GLUE备注',
`add_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- xxl_job_registry 执行器注册表
CREATE TABLE `xxl_job_registry` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`registry_group` varchar(50) NOT NULL,
`registry_key` varchar(255) NOT NULL,
`registry_value` varchar(255) NOT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `i_g_k_v` (`registry_group`,`registry_key`,`registry_value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- xxl_job_group 执行器信息表
CREATE TABLE `xxl_job_group` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`app_name` varchar(64) NOT NULL COMMENT '执行器AppName',
`title` varchar(12) NOT NULL COMMENT '执行器名称',
`address_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行器地址类型:0=自动注册、1=手动录入',
`address_list` text COMMENT '执行器地址列表,多地址逗号分隔',
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- xxl_job_user 用户表
CREATE TABLE `xxl_job_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '账号',
`password` varchar(50) NOT NULL COMMENT '密码',
`role` tinyint(4) NOT NULL COMMENT '角色:0-普通用户、1-管理员',
`permission` varchar(255) DEFAULT NULL COMMENT '权限:执行器ID列表,多个逗号分隔',
PRIMARY KEY (`id`),
UNIQUE KEY `i_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- xxl_job_lock 任务锁表
CREATE TABLE `xxl_job_lock` (
`lock_name` varchar(50) NOT NULL COMMENT '锁名称',
PRIMARY KEY (`lock_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 初始化默认管理员账号(admin/123456)
INSERT INTO `xxl_job_group` (`id`, `app_name`, `title`, `address_type`, `address_list`, `update_time`)
VALUES (1, 'yudao-server', 'RuoYi Office', 0, NULL, NOW());
INSERT INTO `xxl_job_user` (`id`, `username`, `password`, `role`, `permission`)
VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, NULL);
INSERT INTO `xxl_job_lock` (`lock_name`) VALUES ('schedule_lock');
COMMIT;💡 注意:初始化数据中已包含
yudao-server执行器,无需手动添加。
方式 2:从 GitHub 下载
# 下载 XXL-Job 2.4.0 官方建表 SQL
curl -o tables_xxl_job.sql https://raw.githubusercontent.com/xuxueli/xxl-job/2.4.0/doc/db/tables_xxl_job.sql1.2 执行建表 SQL
如果 MySQL 运行在 Docker 中:
# 将 SQL 文件复制到 MySQL 容器内
docker cp tables_xxl_job.sql mysql:/tmp/
# 进入 MySQL 执行
docker exec -it mysql mysql -uroot -p'你的MySQL密码'
# 在 MySQL 命令行中执行
source /tmp/tables_xxl_job.sql;如果使用 MySQL 客户端连接:
mysql -h 127.0.0.1 -P 3306 -uroot -p'你的MySQL密码' < tables_xxl_job.sql1.3 验证数据库
docker exec -it mysql mysql -uroot -p'你的MySQL密码' -e "USE xxl_job; SHOW TABLES;"应看到以下 8 张表:
+--------------------+
| Tables_in_xxl_job |
+--------------------+
| xxl_job_group |
| xxl_job_info |
| xxl_job_lock |
| xxl_job_log |
| xxl_job_log_report |
| xxl_job_logglue |
| xxl_job_registry |
| xxl_job_user |
+--------------------+步骤 2:Docker 部署 XXL-Job Admin
2.1 拉取镜像
# 方式 1:直接拉取(需配置镜像加速器或网络通畅)
docker pull xuxueli/xxl-job-admin:2.4.0
# 方式 2:使用国内镜像源
docker pull registry.cn-hangzhou.aliyuncs.com/xuxueli/xxl-job-admin:2.4.0
docker tag registry.cn-hangzhou.aliyuncs.com/xuxueli/xxl-job-admin:2.4.0 xuxueli/xxl-job-admin:2.4.0
# 方式 3:手动导入(网络不通时)
# 在有网络的机器上执行:
# docker pull xuxueli/xxl-job-admin:2.4.0
# docker save xuxueli/xxl-job-admin:2.4.0 -o xxl-job-admin-2.4.0.tar
# 传输到服务器后导入:
# docker load -i xxl-job-admin-2.4.0.tar验证镜像:
docker images | grep xxl-job2.2 创建日志目录
mkdir -p /data/xxl-job/logs2.3 启动 XXL-Job Admin 容器
⚠️ 请根据实际情况修改以下参数:
- MySQL 地址(如 MySQL 也在同一台 Docker 宿主机,可用
host.docker.internal或宿主机内网 IP) - MySQL 用户名和密码
- accessToken 需与后端项目配置保持一致(项目默认
default_token)
场景 A:MySQL 在同一台宿主机的 Docker 中运行
# 获取宿主机内网 IP(用于容器间通信)
HOST_IP=$(hostname -I | awk '{print $1}')
echo "宿主机 IP: $HOST_IP"
docker run -d \
--name xxl-job-admin \
--restart always \
-p 9090:8080 \
-v /data/xxl-job/logs:/data/applogs \
-e TZ=Asia/Shanghai \
-e PARAMS=" \
--spring.datasource.url=jdbc:mysql://${HOST_IP}:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai \
--spring.datasource.username=root \
--spring.datasource.password=你的MySQL密码 \
--xxl.job.accessToken=default_token \
--xxl.job.logretentiondays=30 \
" \
xuxueli/xxl-job-admin:2.4.0场景 B:MySQL 在远程服务器
docker run -d \
--name xxl-job-admin \
--restart always \
-p 9090:8080 \
-v /data/xxl-job/logs:/data/applogs \
-e TZ=Asia/Shanghai \
-e PARAMS=" \
--spring.datasource.url=jdbc:mysql://MySQL服务器IP:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai \
--spring.datasource.username=root \
--spring.datasource.password=你的MySQL密码 \
--xxl.job.accessToken=default_token \
--xxl.job.logretentiondays=30 \
" \
xuxueli/xxl-job-admin:2.4.0场景 C:本地开发环境(Windows / Mac)
docker run -d \
--name xxl-job-admin \
--restart always \
-p 9090:8080 \
-v xxl-job-logs:/data/applogs \
-e TZ=Asia/Shanghai \
-e PARAMS=" \
--spring.datasource.url=jdbc:mysql://host.docker.internal:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai \
--spring.datasource.username=root \
--spring.datasource.password=你的MySQL密码 \
--xxl.job.accessToken=default_token \
--xxl.job.logretentiondays=30 \
" \
xuxueli/xxl-job-admin:2.4.0💡 Windows/Mac 上 Docker 容器访问宿主机 MySQL:使用
host.docker.internal代替127.0.0.1。
2.4 验证启动
# 检查容器状态
docker ps | grep xxl-job-admin
# 查看启动日志
docker logs -f xxl-job-admin --tail 100
# 等待出现类似日志表示启动成功:
# 2026-xx-xx ... Started XxlJobAdminApplication in x.xxx seconds2.5 访问管理界面
浏览器打开:
http://服务器IP:9090/xxl-job-admin本地开发环境:
http://127.0.0.1:9090/xxl-job-admin默认登录账号:
| 账号 | 密码 |
|---|---|
| admin | 123456 |
步骤 3:修改后端项目配置
打开 yudao-server/src/main/resources/application-local.yaml,找到 XXL-Job 配置段,将 enabled 改为 true:
--- #################### 定时任务相关配置 ####################
xxl:
job:
enabled: true # ← 改为 true,开启 XXL-Job 执行器
admin:
addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心地址⚠️ 如果 XXL-Job Admin 部署在远程服务器,需修改
addresses为对应 IP 地址。
修改完成后 重启后端服务。
步骤 4:配置执行器
重启后端服务后,执行器会自动注册到 XXL-Job Admin。
4.1 验证执行器注册
- 登录 XXL-Job Admin(
http://127.0.0.1:9090/xxl-job-admin) - 进入 执行器管理 菜单
- 应看到已注册的执行器:
| AppName | 名称 | 注册方式 | 机器地址 |
|---|---|---|---|
| yudao-server | RuoYi Office | 自动注册 | 192.168.x.x:9999 |
如果执行器未自动出现,点击 新增 手动添加:
- AppName:
yudao-server(必须与配置一致)- 名称:
RuoYi Office- 注册方式:自动注册
步骤 5:配置定时任务
5.1 添加任务
在 任务管理 菜单中,选择执行器 RuoYi Office,点击 新增。
以 每日自动生成打卡记录 为例:
| 配置项 | 值 |
|---|---|
| 执行器 | RuoYi Office |
| 任务描述 | 每日自动生成打卡记录 |
| 负责人 | admin |
| 路由策略 | 第一个 |
| Cron | 0 5 0 * * ? |
| 运行模式 | BEAN |
| JobHandler | punchRecordGenerateJob |
| 阻塞处理策略 | 单机串行 |
| 任务超时时间 | 0 |
| 失败重试次数 | 1 |
点击 保存。
5.2 常用任务配置参考
| 任务描述 | JobHandler | 建议 Cron | 说明 |
|---|---|---|---|
| 每日自动生成打卡记录 | punchRecordGenerateJob | 0 5 0 * * ? | 每天 00:05 |
| 员工调动生效处理 | employeeTransferByEffectiveDateJob | 0 0 1 * * ? | 每天 01:00 |
| 员工离职生效处理 | employeeResignationByResignationDateJob | 0 30 1 * * ? | 每天 01:30 |
| 客户自动回收公海 | customerAutoPutPoolJob | 0 0 2 * * ? | 每天 02:00 |
| 支付订单同步 | payOrderSyncJob | 0 0/1 * * * ? | 每分钟 |
| 支付订单过期 | payOrderExpireJob | 0 0/1 * * * ? | 每分钟 |
| 退款同步 | payRefundSyncJob | 0 0/1 * * * ? | 每分钟 |
| 支付通知 | payNotifyJob | 0 0/1 * * * ? | 每分钟 |
| 访问日志清理 | accessLogCleanJob | 0 0 3 * * ? | 每天 03:00 |
| 错误日志清理 | errorLogCleanJob | 0 0 4 * * ? | 每天 04:00 |
5.3 启动任务
在任务列表中,点击任务右侧的 启动 按钮。
也可以点击 执行一次 立即测试任务是否正常执行。
故障排查
执行器注册不上
现象:执行器管理中看不到 yudao-server,或机器地址为空。
排查步骤:
# 1. 确认后端 xxl.job.enabled 为 true
grep -A 5 "xxl:" yudao-server/src/main/resources/application-local.yaml
# 2. 确认 Admin 地址配置正确
# addresses 需要能从后端服务访问到
# 3. 确认 accessToken 一致
# Admin 容器启动参数中 --xxl.job.accessToken=default_token
# 后端配置 xxl.job.accessToken: default_token
# 4. 查看后端启动日志,搜索 xxl-job 相关
# 正常应该看到:
# >>>>>>>>>>> xxl-job register jobhandler success, name:punchRecordGenerateJobAdmin 启动失败
# 查看容器日志
docker logs xxl-job-admin
# 常见错误:
# 1. 数据库连接失败 → 检查 MySQL 地址、用户名、密码
# 2. Access denied → 检查 MySQL 用户权限
# 3. Unknown database 'xxl_job' → 建表 SQL 未执行任务执行失败
- 在 调度日志 中查看具体错误信息
- 常见原因:
- 调度成功,执行失败:检查后端业务逻辑日志
- 调度失败:执行器不在线,检查注册状态
- 路由策略异常:只有一个执行器实例时使用 "第一个" 策略
容器管理常用命令
# 查看容器状态
docker ps | grep xxl-job-admin
# 查看日志
docker logs -f xxl-job-admin --tail 200
# 重启容器
docker restart xxl-job-admin
# 停止并删除容器
docker stop xxl-job-admin
docker rm xxl-job-admin
# 重新部署(修改配置后)
docker stop xxl-job-admin && docker rm xxl-job-admin
# 然后重新执行 docker run 命令服务地址速查
| 服务 | 地址 | 账号 |
|---|---|---|
| XXL-Job Admin | http://服务器IP:9090/xxl-job-admin | admin / 123456 |
| 后端 API | http://服务器IP:48080 | - |
注意事项
- 版本对齐:XXL-Job Admin 版本必须与项目依赖版本一致,当前为
2.4.0 - Token 一致:Admin 的
--xxl.job.accessToken必须与后端配置xxl.job.accessToken一致(默认default_token) - 时区设置:Admin 容器已通过
-e TZ=Asia/Shanghai设置为东八区,确保 Cron 表达式按北京时间调度 - 日志保留:
--xxl.job.logretentiondays=30设置日志保留 30 天,可根据磁盘空间调整 - 多环境部署:生产环境建议将
accessToken修改为复杂随机字符串
