如何防止 cron 任务重复(并发)执行?

任务执行时间超过调度间隔会导致并发重叠。标准解法:flock -n 锁文件——上一个没跑完,新的直接跳过。本文给出用法、脚本内置锁与应用内幂等设计。

最佳实践
如何防止 cron 任务重复(并发)执行?封面

标准解法:用 flock——* * * * * /usr/bin/flock -n /tmp/job.lock /path/to/job.sh。它给锁文件加排他锁:上次任务没跑完锁还在,新一轮直接跳过(-n 非阻塞),跑完自动释放。执行时长超过调度间隔的任务都必须加这层保护。

flock 用法

* * * * * /usr/bin/flock -n /tmp/backup.lock /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
  • -n:拿不到锁立即退出(不加则等待,可能越堆越多)
  • 锁文件任意路径,建议 /tmp 或 /run(重启自动清)
  • 想记录"被跳过":-n 退出码为 1,可包一层记日志

脚本内置锁(自带防重入)

不想依赖 crontab 写法,把锁写进脚本:

#!/bin/bash
exec 200>/tmp/myjob.lock          # 打开文件描述符 200
flock -n 200 || { echo "$(date) 上一个实例还在跑,跳过"; exit 1; }

# 正常任务逻辑

好处:怎么调用(cron、手动、其他调度器)都受保护。

其他可选方案

方案 说明
systemd timer OnCalendar 触发的 service 默认不并发(上一个没结束不启新实例)
应用内分布式锁 Redis SETNX/数据库锁,多机部署时必须用这个,flock 只管单机
PID 文件自检 脚本开头查 PID 文件有效性,老派写法

多机场景的特别提醒

flock 只防单机并发。同一个任务在多台的 crontab 里都配了(高可用部署常见),要用 Redis/数据库级的分布式锁,或让任务只在 leader 节点跑;更省心的是把这类任务收敛到一台/一个 K8s CronJob。

观测云对照

并发重叠在数据里看得见。 任务执行时长超过间隔的趋势(观测云里看任务日志的开始/结束时间差)是加锁需求的早期信号;被 flock 跳过的次数也可打点统计,长期跳过多说明该优化任务耗时了。

常见问题(FAQ)

Q:flock 的锁文件要定期清理吗?
A:不用。锁是加在打开的文件句柄上的,文件本身留着无妨;放 /tmp 或 /run 重启自清。

Q:任务卡死了锁永远不释放?
A:进程退出(包括被 kill)锁自动释放;flock 不会死锁残留。但任务本身卡死要另外加超时(timeout 300 job.sh)。

Q:想"排队执行"而不是"跳过"?
A:去掉 -n,新实例会等锁释放再跑;注意大量堆积的风险,一般跳过+告警更合理。

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台