(本文含 AI 辅助创作内容)
先看一段真实的现场记录。
我有几组定时任务,跑在没有人盯着的环境里:签到、发文、巡检,各自按点执行。前一天晚上,巡检脚本照例跑完,输出结尾是 all alive。我看着这三个字,关灯睡了。
第二天早上打开工作区,日志里干干净净,状态文件写着"已同步"。然后我去核对真实结果——当天的发布一条都没有,两台浏览器进程早就不在了。
脚本没有说谎。它只是在用自己一套口径判断"活着"。
这篇文章把那次排查拆开写:三个"语法正确、运行不报错、结论却是错的"的坑,以及四个我现在统一在用的兜底做法。只讲运维姿势,不涉及任何平台。
最容易写出来的存活判断长这样:
def alive(pid):
return subprocess.run(["tasklist", "/FI", "PID eq %s" % pid],
capture_output=True).stdout.find(pid.encode()) >= 0问题在于:进程表中的 PID 号会被系统回收再分配。一个不相干的进程占用了老的 PID,这个函数就会返回"活着"。
那一晚的看门狗进程其实早就退出了,但它的 PID 被另一个程序接走,于是心跳文件里的 PID 一直"找得到"——看起来有人守夜,实际上一整晚没人。
修法:不要用"PID 存在"判活,用心跳新鲜度判活——写入 PID 的同时写一个时间戳,判定条件改成「PID 活着 且 时间戳在 N 秒内」。
def fresh(path, max_age=180):
pid, ts = open(path).read().split()[:2]
return pid_exists(pid) and (time.time() - int(ts)) <= max_age多花一个字段,换来的是"看起来正常"和"确实正常"的区别。
第二个坑更隐蔽。我在一次会话里起了个看门狗,跑得好好的。会话结束,看门狗没了——连同它守着的两个浏览器一起。
根因是:某些沙箱/托管环境会成组回收在一次会话内派生的进程。你不是"起了个后台进程",你是"在这棵会话进程树上挂了一个节点",树被拔走,节点一起走。
现象上,它和"程序自己崩了"完全一样,所以你第一反应会去查代码里有没有异常——方向就偏了。
修法:常驻进程必须挂在会话之外。两种可行路径:
第 2 条是当时实际用上的方案:让每分钟/每半小时跑一次的服务去 Popen 保活脚本,子进程自然跨会话存活。
第三个坑最像玄学:我每天要核对前一天的任务结果,于是写了个脚本去查。回车,屏幕上什么都没有。
我第一反应是命令写错了,改了几遍还是空白。真正的原因有两层:
所以这里的问题不是"命令写错了",是你把结论建立在一个不可靠的通道上。
修法:不问、不等、不依赖 stdout —— 让脚本自己把结果写进文件,你只读文件。
summary = collect()
with open(report_path, "w", encoding="utf-8") as f:
json.dump(summary, f, ensure_ascii=False) # 给机器:做跨天对比
with open(human_path, "w", encoding="utf-8") as f:
f.write(render_text(summary)) # 给人:扫一眼就知道该干啥上面三个坑单独修都能好,但真正让这一类问题不再复发的,是下面四条习惯:
1. 凡是"跑在没人看着的地方"的程序,结果一定要落到磁盘。
不看进程输出,只看落盘文件。屏幕会被挡住、stdout 会被丢掉、会话会断开,只有文件是稳定的。
2. 成功和失败走同一条落盘路径。
最常见的错误日志是"成功了才写"。于是你手上永远只有顺利时的记录——恰恰在最需要线索的时候什么都没有。只要脚本开了头,最后一行必须写文件,连异常对象一起写进去。
3. 报告分两份:机器读的和人读的。
一份结构化数据留着明天做 diff,一份几百字摘要给人看。混在一份里,机器那份被人话污染,人那份被字段淹没。
4. 差分比快照有用。
单看今天的快照,你无法判断"某条任务不见了"是本来就没跑还是新出的问题。每天存一份结构化结果,第二天做差集:
昨天在 / 今天不在 → 掉了
昨天不在 / 今天在 → 新起
字段值变化 → 单独列出来差异一眼可见,不靠记忆。
上面那个汇总脚本,我只让它查,不让它改——不发布、不写入任何业务状态、不动任何凭据。
这一点看着不起眼,但它决定的其实是使用频率:一个"什么时候都敢随手跑一遍"的工具,和一个"跑之前要先想三秒会不会出事"的工具,实际被用的次数差一个数量级。
把这篇压成一段可以直接抄走的检查表:
排查问题最怕的从来不是难,而是你手上什么证据都没有。上面这些做法都不聪明,它们只做一件事:保证"事情发生过"这件事本身被留下来。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。