根本原因是stderr未捕获导致错误静默,需重定向2>&1、脚本内用try-except+raise确保非零退出码,并辅以锁文件看门狗机制。

这个问题本质是“任务看似成功,实则中途崩溃”,根源在于标准错误(stderr)未被捕获、未被记录、也未触发告警。系统只看到进程退出码为 0,就判定成功——而 Python 或 Shell 脚本里一个未捕获的异常、一个模块导入失败、一个网络超时,都可能静默吞掉错误并意外退出,却没留下任何线索。
强制重定向 stderr 到日志文件
crontab 默认不继承终端的 stderr 输出,必须显式重定向。仅用 >> log.txt 只捕获 stdout,stderr 仍会丢失。
- 正确写法:
0 3 * * * /usr/bin/python3 /opt/autoglm/job.py >> /var/log/autoglm/job.log 2>&1 - 更健壮写法(带时间戳):
0 3 * * * /usr/bin/python3 /opt/autoglm/job.py >> /var/log/autoglm/job.log 2>&1 && echo "[$(date +'%Y-%m-%d %H:%M:%S')] OK" >> /var/log/autoglm/job.log || echo "[$(date +'%Y-%m-%d %H:%M:%S')] FAILED" >> /var/log/autoglm/job.log
脚本内主动捕获并记录所有异常
不能依赖外部重定向兜底。Python 脚本应在顶层用 try-except 包裹主逻辑,并强制写入 stderr 和日志文件。
- 在脚本开头添加:
import sys, traceback; sys.stderr = open('/var/log/autoglm/job.err', 'a') - 主入口包裹:
if __name__ == "__main__": try: main() except Exception as e: traceback.print_exc(); raise - 关键:
raise确保非零退出码,让 crontab 或 systemd 能感知失败
用 exit code 做最终可信信号
系统判断“是否成功”的唯一依据是进程退出码。只要脚本最后返回 0,无论中间抛了多少异常,都被视为成功。
- 避免在异常处理中静默 return(等价于 return 0)
- 所有关键步骤后加简单校验,例如:
if not os.path.exists(output_file): sys.exit(1) - 对调用子命令(如 subprocess.run)务必检查
result.returncode,不为 0 就主动sys.exit(1)
引入轻量级执行健康看门狗
光靠日志还不够——得有“主动心跳”或“结果存在性验证”。适合高可靠性场景:
- 脚本开头写一个临时标记文件:
open('/tmp/job_running.lock', 'w').close() - 脚本结尾删除它;若 10 分钟后该文件仍存在,说明崩溃卡死
- 另配一个每 5 分钟检查的守护脚本,发现残留锁文件就发告警、杀进程、清状态











