15 · 定时任务
日报推送、账单结算、缓存预热、数据清理——这些不靠用户触发,靠定时任务。本篇从单机 cron 讲到分布式调度,并用你正在接触的 XXL-Job 做类比。
速览卡
| 项 | 内容 |
|---|---|
| 一句话定位 | 定时任务从"单机能跑"到"分布式不重不漏"的完整台阶 |
| 核心内容 | cron 与进程内调度、单机方案(APScheduler)、分布式调度的核心问题、XXL-Job 概念类比、幂等与补偿 |
| 读完能回答 | 定时任务该放哪跑?多实例会不会重复执行?XXL-Job 那些概念到底解决什么问题? |
| 相关板块 | C06 · 异步与消息 | C04 · 一致性与事务 | C17 · 部署与 CI/CD |
一、先分清:定时任务 ≠ 消息队列
| 维度 | 定时任务 | 消息队列 |
|---|---|---|
| 触发 | 时间(cron) | 事件(有消息就执行) |
| 典型场景 | 每天 3 点结算 | 下单后发通知 |
| 延迟 | 固定节奏 | 即时 |
两者常混用,但本质不同:定时任务是"到点干活",MQ 是"有活就干"。详见 C06。
二、单机方案
2.1 系统 cron
cron
0 3 * * * /usr/bin/python /app/jobs/settlement.py简单、可靠,但只能单机、没有失败重试、没有监控。适合"不重要的维护任务"。
2.2 进程内调度:APScheduler
python
from apscheduler.schedulers.background import BackgroundScheduler
scheduler = BackgroundScheduler()
@scheduler.scheduled_job("cron", hour=3, minute=0)
def settlement():
...
scheduler.start()优点:代码里定义、可重试。缺点:多实例部署会重复执行——这是迈向分布式的第一步。
三、分布式调度的核心问题
应用实例从 1 个变 3 个后,定时任务会遇到三个问题:
| 问题 | 现象 | 解法 |
|---|---|---|
| 重复执行 | 三个实例各跑一遍 | 分布式锁 / 主节点选主 |
| 没有重试 | 跑挂就丢了 | 任务记录 + 重试策略 |
| 没有监控 | 悄悄失败没人知道 | 日志/告警接入 |
3.1 用 Redis 分布式锁防重复
python
def run_once(key, ttl=60):
# 拿到锁才执行,拿不到说明别的实例在跑
if not redis.set(f"job:{key}", "1", nx=True, ex=ttl):
return
do_work()这是"自研调度"的最小方案,够小项目用。规模再大就交给调度框架。
四、XXL-Job 概念类比
你正在接触的 XXL-Job 就是"分布式调度框架",它的核心概念用前端思维解释:
| XXL-Job 概念 | 是什么 | 前端类比 |
|---|---|---|
| 执行器(Executor) | 真正干活的服务 | worker 进程 |
| 调度中心(Admin) | 管"什么时候派活" | 任务调度器/消息中心 |
| 任务 / Handler | 一个可调度的函数 | 一个可执行的任务函数 |
| 路由策略 | 活派给哪个实例(轮询/一致性哈希/广播) | 负载均衡策略 |
| 失败重试 | 失败自动重跑 N 次 | 重试机制 |
| 分片广播 | 大任务拆给多个实例各干一部分 | MapReduce 思想 |
一句话:XXL-Job = 定时任务的"调度中心 + 注册中心 + 重试/监控",你写的
@XxlJob("xxx")就是注册一个可被调度执行的任务。
五、幂等与补偿
无论单机还是分布式,定时任务必须幂等——因为可能重试、可能重复执行:
| 手段 | 说明 |
|---|---|
| 唯一约束 | 任务写库时用业务唯一键,重复执行撞约束即跳过 |
| 状态机 | 任务记录从 pending → running → done,重跑只处理 pending |
| 可重入 | 每个步骤设计成"重复执行结果一样" |
python
def settlement():
for order in pending_orders():
if mark_done(order.id): # UPDATE ... WHERE status='pending'
do_settle(order) # 只有这次抢到 pending 的才处理与 C04 的幂等设计是一套方法论,定时任务只是更依赖它。
自检清单
- [ ] 能说清定时任务与消息队列的区别
- [ ] 能用 APScheduler 或系统 cron 跑一个单机任务
- [ ] 能说清多实例下"重复执行"问题及分布式锁解法
- [ ] 能说出 XXL-Job 的执行器/调度中心/路由策略各解决什么
- [ ] 会给任务做幂等(状态机或唯一约束)
常见误区
- 误区:定时任务多实例跑没事。 不防重会重复扣款、重复发券,必须幂等或加锁。
- 误区:任务失败就完了。 要有重试和告警,否则线上悄悄丢任务。
- 误区:拿 MQ 当定时任务用。 场景不同,延迟队列不等于定时调度。
- 误区:定时任务只能放后台进程。 也可以接在请求里触发检查,但别阻塞主流程。
动手练习
练习 A:每日结算
写一个"每日 3 点结算订单"的 APScheduler 任务,带 pending → done 状态机防重。
练习 B:分布式锁防重
起两个进程同时跑同一个任务,用 Redis 锁验证只有一个真正执行。
练习 C:映射 XXL-Job
对照你项目的 @XxlJob 代码,标注每个 handler 对应本文的哪个概念,写一段解释。
相关文档
本区
- 06 · 异步与消息 —— 定时任务 vs 消息队列
- 04 · 一致性与事务 —— 幂等与补偿
- 08 · 可观测性 —— 任务失败要能看见
其他域
- 05 · 工程化与 LLMOps —— 模型刷新/评估任务