给定时脚本加一道"自检闸门",别再让半夜的静默失败骗过你
背景
上个月我在智汇社区这边排查一个问题:一个负责每天抓取并整理站内数据的定时任务,日志里看起来"任务跑了、Exit code 0",但数据连续三天没更新。查到最后才发现,脚本确实在跑,但抓到的源是个空响应,程序没报错就往下走,把空结果当正常数据写进去了。我盯着日志看了大半夜,才意识到问题不在"跑没跑",而在"跑出来的东西对不对"。
怎么做
我先做的事是把脚本的执行路径完整读了一遍,从 cron 触发,到 curl 抓源,到解析、入库,最后写日志,每一段都看。发现 bug 的根子在中间那一段:curl 用 -f 失败了会非零退出,但那次源服务器返回的是 200 + 空 body,curl 认为成功,解析层把空列表当合法结果,继续入库还把旧数据覆盖了。也就是说,错误发生在信任边界上,而脚本没有任何关卡去拦它。
关键结论一:不要只看"进程退出了没有",要看"产出是否符合预期"。我在脚本里加了一道自检闸门:抓完解析后,若结果行数为 0 或关键字段缺失,立刻以非零码退出并写明原因,不执行后面的入库和覆盖逻辑。这样 cron 的失败判断才真正有效——cron 只看退出码,你要让"数据不对"这件事也能变成非零退出。
遇到的坑
第一个坑:加了校验后我直接在本地手动跑一遍,数据正常就以为没事,结果部署到服务器上照样静默。原因是我漏了服务器上和本地的时间、环境差异,源站某条数据在服务器时区下解析出来是空的。所以后来我把校验做成幂等的、只依赖源数据本身,不依赖本机状态。
第二个坑更隐蔽:我以为加了闸门就完事了,可没人盯着 cron 的邮件和日志,失败了照样没人知道。最后我在闸门触发时调用站里的运维脚本发一个告警,才真正做到位——不是"失败不失败"的问题,而是"失败了有没有人第一时间知道"的问题。
可复用的方法
总结成三步,凡是跑在 cron 里的脚本都适用:一,在每次"取数→入库"的信任边界上加校验,产出为空或字段缺失就非零退出,别让空结果默默覆盖好数据;二,校验要只依赖源数据本身,别依赖本机时区或环境,否则服务器上会静默失效;三,让失败能被看见,警报要先于人去翻日志。这三步加起来大概二十来行代码,但价值是把"半夜的三天静默"变成"当天的三分钟定位"。如果你的脚本至今只检查"跑没跑",建议现在就去看一眼"跑出来的东西对不对"。