<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>AI运维 on Kalend's Blog</title><link>https://blog.kalend.top/categories/ai%E8%BF%90%E7%BB%B4/</link><description>Recent content in AI运维 on Kalend's Blog</description><generator>Hugo -- gohugo.io</generator><language>zh</language><lastBuildDate>Sun, 11 Oct 2026 08:45:00 +0800</lastBuildDate><atom:link href="https://blog.kalend.top/categories/ai%E8%BF%90%E7%BB%B4/index.xml" rel="self" type="application/rss+xml"/><item><title>让AI自己发现Bug：我给20个定时任务装了看门狗</title><link>https://blog.kalend.top/2026/10/11/2026-10-11-ai-watchdog-cron-tasks.html/</link><pubDate>Sun, 11 Oct 2026 08:45:00 +0800</pubDate><guid>https://blog.kalend.top/2026/10/11/2026-10-11-ai-watchdog-cron-tasks.html/</guid><description>
 &lt;blockquote&gt;
 &lt;p&gt;家里服务器上有20个定时任务每天替我干活。真正吓人的不是它们不跑，而是跑了、出错了、结果没送到——我却一直蒙在鼓里。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="先说结论"&gt;先说结论
&lt;/h2&gt;&lt;p&gt;给定时任务装看门狗，核心就三条：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;异常才报&lt;/strong&gt;：状态文件去重，正常情况闭嘴&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;同一件事只报一次&lt;/strong&gt;：版本号没变就静默&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;能自愈就不等人&lt;/strong&gt;：小问题自动修，修不好再喊人&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;三个设计都是几十行shell，没有框架，没有依赖。&lt;/p&gt;
&lt;h2 id="背景我机上的20个定时任务"&gt;背景：我机上的20个定时任务
&lt;/h2&gt;&lt;p&gt;先交代现场。&lt;code&gt;jobs.json&lt;/code&gt;里躺着20个任务，代表性几个：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;任务&lt;/th&gt;
					&lt;th&gt;节奏&lt;/th&gt;
					&lt;th&gt;干什么&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;系统健康巡查&lt;/td&gt;
					&lt;td&gt;每天 08:05&lt;/td&gt;
					&lt;td&gt;巡检脚本，结果直发我&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;磁盘空间看门狗&lt;/td&gt;
					&lt;td&gt;每 120 分钟&lt;/td&gt;
					&lt;td&gt;磁盘/inode 异常才报&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;版本监控&lt;/td&gt;
					&lt;td&gt;每 6 小时&lt;/td&gt;
					&lt;td&gt;有新版本才提示&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;任务自动修复器&lt;/td&gt;
					&lt;td&gt;每 120 分钟&lt;/td&gt;
					&lt;td&gt;卡住的任务自动诊断修复&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;更新检查（RTK）&lt;/td&gt;
					&lt;td&gt;每周一 10:00&lt;/td&gt;
					&lt;td&gt;检查新版本并自动升级&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;DNS健康检查&lt;/td&gt;
					&lt;td&gt;每 5 分钟&lt;/td&gt;
					&lt;td&gt;域名解析异常告警&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;任务多了以后，两个问题浮出水面。&lt;/p&gt;
&lt;h2 id="为什么裸定时任务不可靠"&gt;为什么裸定时任务不可靠
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;坑一：报警疲劳。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;磁盘看门狗第一版，每次运行都报一遍。磁盘明明是正常的，也照样发消息。&lt;/p&gt;
&lt;p&gt;一周之后我就麻木了。报警刷屏的结局是：真出事那天，警报混在一堆&amp;quot;一切正常&amp;quot;里，被我随手划掉。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;坑二：跑了，不等于知道了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是更隐蔽的坑。我翻了投递记录：236条投递里，&lt;strong&gt;88条发送失败&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;任务确实跑了，结果也生成了，但最后一步&amp;quot;送到我眼前&amp;quot;失败了。日志里的原因很统一：会话没就绪。&lt;/p&gt;
&lt;p&gt;最惨的一次：某天早上连续4个任务投递失败，我到中午才知道当天有一堆事发生。&lt;/p&gt;
&lt;h2 id="设计1磁盘看门狗异常才报"&gt;设计1：磁盘看门狗，异常才报
&lt;/h2&gt;&lt;p&gt;v2的核心是一个状态文件，只存一行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;0 27
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;含义：上次已报级别0（正常），当时使用率27%。&lt;/p&gt;
&lt;p&gt;判断逻辑：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;当前状态&lt;/th&gt;
					&lt;th&gt;动作&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;级别升级（0→1、0→2、1→2）&lt;/td&gt;
					&lt;td&gt;报警&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;同级别&lt;/td&gt;
					&lt;td&gt;静默退出&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;降回正常&lt;/td&gt;
					&lt;td&gt;报一次&amp;quot;已恢复&amp;quot;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;阈值：磁盘 ≥90% 严重，≥75% 警告；inode ≥80% 也算严重。&lt;/p&gt;
&lt;p&gt;触发时不是干巴巴一句&amp;quot;磁盘满了&amp;quot;，而是直接附上排查现场：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用率和剩余空间&lt;/li&gt;
&lt;li&gt;&lt;code&gt;du&lt;/code&gt; 排出全盘最大目录 Top8&lt;/li&gt;
&lt;li&gt;/root 下大头 Top5&lt;/li&gt;
&lt;li&gt;可清理项快照（缓存、npm、docker占用量）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实测当前状态：根分区 295G 用了 74G（27%），inode 用 5%，级别 0，静默。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键思想：报&amp;quot;变化&amp;quot;，不报&amp;quot;状态&amp;quot;。&lt;/strong&gt; 人只对变化敏感。&lt;/p&gt;
&lt;h2 id="设计2版本监控每个新tag只报一次"&gt;设计2：版本监控，每个新tag只报一次
&lt;/h2&gt;&lt;p&gt;版本监控的烦恼不一样：它一天扫好几次，同一个版本会被反复发现。&lt;/p&gt;
&lt;p&gt;解法还是状态文件，这次存JSON：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;notified_tag&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;v2026.9.21&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;扫到新tag时：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;和已通知的tag比对，相同就静默退出&lt;/li&gt;
&lt;li&gt;不同才算&amp;quot;新版本&amp;quot;，顺带统计增量——&lt;code&gt;git log&lt;/code&gt; 数出commit数和新特性数，一起报出来&lt;/li&gt;
&lt;li&gt;报完把新tag写回状态文件&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;还有一条纪律：&lt;strong&gt;监控只负责说&amp;quot;有新版本&amp;quot;&lt;/strong&gt;。要不要写文章、什么时候升级，是另一套节奏的事。监控和动作解耦，报警才不会变形。&lt;/p&gt;
&lt;h2 id="设计3自动修复器自愈而不只是报警"&gt;设计3：自动修复器，自愈而不只是报警
&lt;/h2&gt;&lt;p&gt;前两个设计解决&amp;quot;报得准&amp;quot;，第三个解决&amp;quot;报了之后谁来做&amp;quot;。&lt;/p&gt;
&lt;p&gt;任务自动修复器每120分钟跑一轮，固定五步：发现 → 诊断 → 修复 → 放行 → 检查上轮修复结果。&lt;/p&gt;
&lt;p&gt;修复前先分类：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;例子&lt;/th&gt;
					&lt;th&gt;处理&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;A类&lt;/td&gt;
					&lt;td&gt;格式错误、错别字、可验证的事实修正&lt;/td&gt;
					&lt;td&gt;自动修，修完放行重审&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;B类&lt;/td&gt;
					&lt;td&gt;观点争议、缺章节、验证不了的事实&lt;/td&gt;
					&lt;td&gt;只通知，等人决定&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;两条安全绳，防止自动修复变成自动闯祸：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每轮最多修3个任务&lt;/li&gt;
&lt;li&gt;同一个任务累计修3次还不过，升级人工，不再重试&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;无限重试的自动化不是自动化，是事故放大器。&lt;/strong&gt; 上限是必需品。&lt;/p&gt;
&lt;h2 id="两个真实故障"&gt;两个真实故障
&lt;/h2&gt;&lt;p&gt;设计再好，也要靠真实故障检验。这两个都是本机日志里挖出来的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;故障一：迟到1小时37分，然后失败。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;更新检查排在每周一10:00。有一周它没按时跑——当天机器磁盘写满，调度器日志里躺着8条&amp;quot;disk is full&amp;quot;。&lt;/p&gt;
&lt;p&gt;这任务直到11:37才被重新拉起，&lt;strong&gt;迟到1小时37分&lt;/strong&gt;，而且拉起后还是没跑成。&lt;/p&gt;
&lt;p&gt;结果就是：那一周的版本检查无声无息地丢了。没有报错，没有重试提示，什么都没有。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;故障二：4连发失败。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;另一天早上七点半到九点，连续4个任务的结果投递全部失败，原因都是会话没就绪。&lt;/p&gt;
&lt;p&gt;4个任务都正常执行了，输出文件都在。但&amp;quot;我&amp;quot;这个终点，什么都没收到。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这两个故障指向同一件事：报警的送达环节本身也需要被监控。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;任务跑了≠你知道了，中间还隔着投递这一跳。现在发送失败的内容都会落盘留底，配上兜底通道，不再静默蒸发。&lt;/p&gt;
&lt;h2 id="可复制的做法总结"&gt;可复制的做法总结
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;先有状态文件，再谈报警&lt;/strong&gt;——一行文本就够&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;报变化，不报状态&lt;/strong&gt;——正常情况保持沉默&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;报警带现场&lt;/strong&gt;——附Top目录、commit数，别让人二次排查&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自愈必须设上限&lt;/strong&gt;——3次修不好就交给人&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;监控你的监控&lt;/strong&gt;——投递失败也要落盘、也要能被发现&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;整套东西最大的一个脚本也只有64行。看门狗的价值不在技术难度，在于承认一个事实：&lt;strong&gt;没有状态记忆的定时任务，只是在假装可靠。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;你的定时任务上一次静默失败是什么时候？翻翻日志，可能会吓一跳。&lt;/p&gt;</description></item></channel></rss>