flock是linux下最直接可靠的部署脚本加锁方式,通过内核级独占锁确保同一时刻仅一个实例运行;推荐在crontab中用flock -xn /tmp/deploy.lock -c 'deploy.sh...'实现非阻塞互斥,锁自动释放,天然适配网络延迟导致的执行时间波动。

用 flock 给部署脚本加独占锁,是最直接、可靠的方式。它不依赖进程名或状态文件,靠内核级文件锁保障同一时刻最多一个实例运行,天然适配网络延迟引发的执行时间不可控问题。
核心写法:在 crontab 里直接包裹 flock
不要在脚本内部加锁,而是在 crontab 调度层控制:
-
推荐写法(非阻塞):
* * * * * flock -xn /tmp/deploy.lock -c '/path/to/deploy.sh >> /var/log/deploy.log 2>&1' -
说明:
-x表示独占锁,-n表示拿不到锁立刻退出(不等待),避免因前次部署卡在网络请求中而堆积任务。
锁文件建议放在/tmp/下,路径必须是绝对路径且所有 cron 实例可访问。
为什么这能应对网络延迟?
自动化部署脚本常因拉镜像、下载包、远程 API 超时等导致耗时剧烈波动。flock 的机制恰好匹配这种不确定性:
- 锁在命令启动时获取,退出时自动释放(哪怕脚本被 kill 或崩溃,内核也会清理)
- 只要上一次部署还没结束,下一轮 cron 触发时
flock -n立即失败,整个命令跳过,不会新建进程 - 无需预估最长执行时间,也不用改 crontab 间隔——节奏交给 cron,互斥交给 flock
增强可观测性的小技巧
让运维能快速确认是否被跳过,或排查锁异常:
- 在命令末尾加简单反馈:
* * * * * flock -xn /tmp/deploy.lock -c '/path/to/deploy.sh >> /var/log/deploy.log 2>&1' || echo "$(date): skipped — lock held" >> /var/log/deploy.log - 手动检查锁状态:
ls -l /proc/$(cat /proc/$(pgrep -f 'flock.*deploy.lock')/fd/* 2>/dev/null | grep deploy.lock | head -1 | awk '{print $9}')/fd
或更简单:看是否有deploy.sh进程正在运行,再结合lsof /tmp/deploy.lock
不推荐的替代方案
有些做法看似简单,但在网络延迟场景下容易失效:
- 用 pgrep 检查进程名:部署脚本若调用 curl/wget/docker pull,子进程可能脱离父进程树,pgrep 漏检;且存在极短竞态窗口(两个 cron 几乎同时通过检测)
- 脚本内自己 touch lockfile + trap rm:异常退出时 trap 可能不触发,导致锁残留,后续所有部署被永久阻塞
- 单纯拉长 crontab 间隔:无法应对偶发超长延迟,要么浪费资源,要么仍可能重叠











