我们常常会有一些定时任务处理的需求,Linux上大多使用Crontab来实现。

趁机记录下最近新开的一台机上使用Crontab的错误排查。

系统是Ubuntu20.04

前置需求

每天定时运行一次虚拟环境下的Python脚本并留存运行日志保存起来。

最初实现

根据需求,很容易写出下面的规则。

crontab -e
# '>>' 代表追加;2>&1 代表错误输出重定向标准输出,即记录所有输出
15 8 * * * ~/XXX/start.sh >> ~/XXX/run.log 2>&1

start.sh内容如下

source venv/bin/activate
python push_main.py

信誓旦旦的等待中,到点后却发现run.log一直都是空的,出现问题了。

错误排查

  1. 首先检查命令。

    ~/XXX/start.sh >> ~/XXX/run.log 2>&1
    

    没问题,正常输出追加log。

  2. 查看Crontab状态和执行日志。

    # 查看Crontab状态
    service cron status
    ...
    # 查看Crontab执行日志
    grep cron /var/log/syslog
    ...
    

    发现时间和本地时间不同,并没有执行命令,方便调试,这里我们调成和本地一样的东八区。

    timedatectl set-timezone Asia/Shanghai
    # 重启系统日志和Crontab使其修改生效
    systemctl restart rsyslog
    service crond restart
    
  3. 时区正确后查看执行日志发现找不到source命令,且找不到venv/bin/activate

    Crontab所用的/bin/sh不包含source命令,用.代替运行脚本即可。

    找不到venv/bin/activate,是因为Crontab执行默认是在用户的根目录下,需要提前手动cd,在start.sh中添加cd ~/XXX/

  4. 导出的log中文自动转码

    Crontab执行的环境变量和用户不同导致的,在start.sh最顶部中添加export LANG=zh_CN.UTF-8导入即可。

修正后的start.sh

export LANG=zh_CN.UTF-8
cd ~/XXX
. venv/bin/activate
python push_main.py

总结

Crontab执行环境和用户执行环境差的有点多,很零碎的参考,记得快忘的也快。