---
title: "把定时任务做稳：锁、重试与幂等"
date: 2026-01-16
category: "后端开发"
---

# 把定时任务做稳：锁、重试与幂等

一月上旬出了个小事故。每天凌晨三点的清理任务，某天数据量突然变大，执行时间超过了调度间隔，第二个实例跟着启动了。

两个进程删同一批数据，一个刚删完，另一个按旧快照再删一遍。日志里全是「记录不存在」，还带出了几次锁等待。凌晨三点十四分，我被告警吵醒。

修法不复杂。任务开头加了文件锁，用 LOCK_NB 非阻塞模式：上一个实例没跑完，这一个直接退出。

```php
$fp = fopen('/tmp/dino-cron.lock', 'c');
if (!flock($fp, LOCK_EX | LOCK_NB)) { exit; }
```

锁解决并发，重试解决失败。第三方接口超时是常态，现在统一改成有限三次、间隔递增，超过上限就记日志，等下一轮调度。

最后一道防线是幂等。删除类任务按条件删，天然可以重跑；统计类从「累加」改成「每次按源数据重算」，重复执行也不会算错。

顺手建了一张执行历史表，记开始时间、结束时间、处理条数。后来排查「任务为什么没生效」，基本一次查询就有答案。

那次之后，凌晨的告警再没响过。