定时任务又双叒没跑?cron 的 5 个经典坑
定时任务又双叒没跑?cron 的 5 个经典坑
服务器上放个定时任务,crontab -e 写一行,看起来再简单不过。但很多人都遇到过:本地测试好好的脚本,一放进 cron 就"人间蒸发"——没报错、没输出,就像从来没存在过。其实 cron 的坑就那么几个,踩过一遍就长记性。
坑一:环境变量和你想的不一样
这是最常见的死因。在终端里跑得好好的脚本,进了 cron 就找不到命令:python3: command not found、docker: command not found。
原因是 cron 的环境极简:PATH 只有 /usr/bin:/bin,你 .bashrc 里配的那些路径、conda 环境、nvm,全都不存在。解决办法二选一:脚本里写绝对路径(/usr/local/bin/python3 而不是 python3);或者在 crontab 开头自己声明:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SHELL=/bin/bash
加了这两行,八成的"找不到命令"问题直接消失。
坑二:相对路径的锅
脚本里写 ./data/input.csv、logs/app.log,手动跑没问题,因为你在项目目录下执行的。cron 可不管你在哪,它的"当前目录"是用户家目录(通常是 /root 或 /home/xxx)。
修复:脚本开头 cd 到固定目录,或者全部用绝对路径。写 crontab 时顺手指定工作目录是最稳的:
0 2 * * * cd /opt/myapp && ./backup.sh >> /var/log/backup.log 2>&1
坑三:输出没地方去,错了也不知道
cron 默认把任务的 stdout/stderr 发邮件给任务 owner。服务器上一般没配邮件服务,输出就直接丢了——任务失败了你都不知道。
习惯:每条 cron 都重定向日志:
*/5 * * * * /opt/check.sh >> /var/log/check.log 2>&1
2>&1 把错误输出也并进去。出问题先看日志,排查效率翻倍。
坑四:时间表达式写错,任务根本没排上
0 2 * * * 是每天凌晨 2 点,* 2 * * * 是 2 点这一小时内每分钟跑一次——差一个星号,行为天差地别。新手常把"每 5 分钟"写成 5 * * * *(那是每小时的第 5 分钟)。
不确定就先用 cron 表达式校验工具过一遍,或者先设成 * * * * * 跑一分钟验证链路通,再改回真实时间。
坑五:任务重叠执行,越跑越慢
一个跑 10 分钟的任务设成每 5 分钟一次,旧进程还没结束新的又起来,越堆越多,最后把机器拖死。对这类任务加文件锁:
*/5 * * * * flock -n /tmp/check.lock /opt/check.sh >> /var/log/check.log 2>&1
flock -n 拿不到锁就直接退出,保证同一时刻只有一个实例在跑。
小结
cron 出问题的排查顺序:先看日志有没有(坑三),再看 PATH 和路径(坑一、坑二),再看时间表达式(坑四),长任务加锁(坑五)。记住一句话:cron 里的世界比你的终端"穷"得多——路径写全、日志留好,定时任务就稳了。
- 点赞
- 收藏
- 关注作者
评论(0)