2026 年 11 月 · 5 分钟阅读
任务红了却没人被叫醒:静默是配置,不是状态

关键定义
静默 任务配置里的一种送达属性,表示正常运行时不通知人。当它同时决定失败时是否通知,红色状态就会被吞掉。
差集对账 把“按计划今天应该有哪些运行”与“实际写出的运行行”相比,差出来的那部分即故障。它要求计划本身可枚举。
缺席检测 对“应该有但没有”的序列告警,而不是对异常指标告警。Prometheus 用 absent 与 absent_over_time 两个函数实现,窗口长度同时决定误报率和发现时延。
十一月十三日早上七点,系统健康自检跑完,判了红。原因是重复库是零字节,巡检层自己在那行输出里写了一句“会被误读成采集没跑”。这句话躺在产物里,从七点躺到下午,没有任何人被叫醒。
同一天还有三件事。盘前数据预取的止损定价环节退出码一,风控位没有刷新。下午两点尾盘提醒连接中断,五分钟后的重跑成功了,第一轮的失败没有人知道。销售心跳每六小时重复一次三十二行的出口未登记错误,连续跑了三十个小时。四起故障,三种类型,事故表里都有记录,而告警时间字段全是空的。
三十小时里的数字
统计窗口从十二日十八点到十三日十八点二十二分。三十小时里,九百三十一次运行被标记为静默不送达,其中七份输出里含明确的 ERROR 或 FAIL 行。四起故障停在“已检测未告警”。另有一张十月十二日的鉴权故障,状态还是“已检测”,告警时间为空,已经停留三十三天。
对照很重要。十一月八日、九日的同类故障都有告警时间。这说明这条链路是后来断掉的,不是从来不存在。同一套系统在一个月前还能把人叫醒,现在不能了,中间发生的是配置的迁移,不是代码的崩溃。
静默本身不是问题。巡检频繁、输出稳定、没有状态变化的任务,本来就该少吵人。问题在判据,判据检查的对象换了。
判据检查错了对象
入库、判断、告警这三步里,第三步的触发条件写的是“这一轮要不要吵人”,不是“这一轮有没有红”。两句话看着相近,指向的东西完全不同:前者是任务的属性,后者是这次运行的结果。属性一旦被写成静默,此后这个任务所有的红色状态都跟着静默。
事故表把“已入库”当成“已通知”。一条记录写进表里,字段 alerted_at 是空的,前端看起来是“已检测”,于是所有人都以为有人知道了。这个误会不需要谁犯错,它只需要没有人去查那个空字段。
断掉的时间点也说明问题。八日、九日还有告警,之后就没了,中间做的是任务配置的迁移:一批任务从默认送达改成按需送达,默认值从“送达”翻成了“不送达”。默认值翻转是最容易被忽略的一次上线,因为没有人会为改一个默认值写测试,也没有人会在评审会上讨论它。
这不是一个字段写错的小问题。每新增一个静默巡检,就等于新增一条只进不出的红色状态。系统越大,这条路越宽,而它是随新增任务自然增长的,不需要任何人主动犯错。
为什么加一条告警规则修不好
最常见的修法是在告警平台加一条规则:“任务失败就通知”。这条规则对带指标的服务有效,对无人值守的批处理无效,因为失败在那里不是指标的变化,是序列的缺席。指标平台对这件事有专门的函数。Prometheus 提供 absent 与 absent_over_time,文档里的原话是,它们用于在某个指标名和标签组合完全不存在时告警。
缺席要被当成一等故障,前提是你先定义“本来应该有什么”。这就是问题的真正位置。可观测性的讨论通常从“采集什么”开始,而无人值守系统的第一个问题是“谁定义预期”,预期存在哪里。存在人脑子里的预期,等于没有预期,因为没有人能对着一张记忆做差集。
还有一层容易被忽略:缺席检测的窗口本身就是成本。窗口设得短,正常波动会误报;设得长,故障的发现时延跟着变长。三十小时里漏掉的这四起故障,如果对账窗口是六小时,最短的那一起要等六小时才被发现,而尾盘提醒那一起的业务价值只有十分钟。
预期要落成一张能查的表
三种排法都试过。第一种,让每个任务在配置里自己声明失败时通知谁,问题是新增任务的人经常忘记声明,而忘记的默认值就是静默。第二种,在告警平台集中写规则,问题和上面一样,规则对指标,不对缺席。第三种,让每一次运行都往一张表里写一行“我跑了,结果是这个”,另有一个对账任务拿“按计划今天应该有哪些行”去比,差集就是故障。
第三种的关键不在对账,在“应该”这两个字必须可枚举。它要求有人把计划本身写成数据:哪个任务、什么节奏、最晚什么时候该有产出。这件事没有技术难度,难在它要求运维把自己的脑子搬进一张表,而且这张表要有人拥有。
最晚产出时间那一列还有个隐含要求:它应该写业务能接受的时延,不是技术上能保证的时间。技术上写十分钟,业务上那个提醒可能只值十分钟,两者一旦错位,对账虽然发现了故障,发现的时候价值已经没了。
我们这一轮就是这么修的。静默任务出现红色状态时,必须破静默,或者被转成一张任务卡进队列;验收判据是近六小时“已检测但未告警”的事故数为零,连续两天成立。这个判据故意写得可数,因为它要能被另一段脚本检查,而不是被人凭印象判断。
谁拥有这张预期表
预期表是这套机制里唯一会腐化的资产。任务下线了,行还留着;任务改了节奏,行没跟着改;新任务上线,行忘了加。三种情况都会让对账报出假故障,假故障多了,人就开始忽略对账结果,机制一路退回到靠人看日志。
所以这张表要有明确的拥有者,而且变更要和任务清单绑在一起。最省事的做法是把“新增任务必须带一行预期”写进上线流程,跟写代码必须带测试一样。这条约束解决的并不是发现速度,它解决的是这张表一年后还有没有意义。
通知渠道自己也会坏
破静默这件事依赖一个前提,送达通道是活的。通道挂掉的时候,任务红、判定正确、消息发不出去,结果和静默一模一样。这层依赖平时看不见,只在出事那天一起出事。
所以兜底不能建立在通道上。现在每天固定时间发一份对账摘要,零故障的那天也发一行,写明今天应有几次运行、实际有几次、差集为空。它的价值不是通知,是证明这条链路还活着。一份每天准时到达的“没有异常”,比一份只在出事时到达的告警更可靠,因为后者无法自证。
产物结构决定可巡检性
这次排查还撞上另一件事。最近三十小时五百零一份任务输出共一百一十五点八万字,其中六十五点五万字是把任务提示词原样回显到产物里,占百分之五十六点六。后果有两层。任何按文本扫描失败信息的巡检,会先撞到大段提示词正文,真实故障行被埋在里面;知识归档把这些提示词当成内容,重复入库。
这是结构缺陷,不是文案问题。产物里应该显式分隔“提示词”和“结果”,否则扫描器的信噪比由作者随手回显多少决定。修法很朴素:产物模板把提示词段落固定成引用块,扫描器只扫结果段;或者干脆不保留提示词。
成本算一趟
漏掉一起故障的代价可以算。一次二十到四十分钟的排查,加上下游被推迟的那段时间。四起故障里,尾盘提醒的那一起如果没人补跑,当天的持仓提醒就整批没发;系统健康自检连红两天,意味着采集链路坏了两天才有人知道,而这两天里的数据缺口要另找证据补。
把三十天里的四起故障摊开,按每起三十分钟处理、每小时两百元算,直接成本四百元。这个数小得可以忽略,所以它从来不是这类问题被修的理由。真正的成本在别处:一条三十三天没人处理的鉴权故障,说明这张事故表已经失去意义,它记录的东西不再有人读。
还有一层不进账的成本。事故表失去意义之后,下一次真出事,团队会先怀疑这张表,而不是先相信它。信任的重建比字段的重建慢得多,中间那段时间里,所有人都知道系统没有可信的记录。
边界与局限
这套做法有规模前提。三十小时九百多次运行,是一家中型公司的量。到了每天几十万次运行,对账表的写放大和差集计算要单独设计,通常按任务分片,并按窗口滚动清理。机制不变,工程量变了。
另一个前提是节奏稳定。如果任务节奏天天在变,“应该有哪些行”每次都要重算,对账的成本会追上收益。这类团队更适合先冻结节奏,再上对账。
还有一类系统不适合这套。需要秒级响应的在线服务,缺席检测的窗口是分钟级的东西,它救不了三秒的超时。对在线服务,缺的是另一套东西,延迟分布和错误率的持续采样。
最后一条代价值得提前说:对账上线会让一批过去没人发现的故障集中出现。第一周报出十几条历史遗留是正常的,不要在这个阶段把窗口调宽把它压下去,压掉的是信号本身。先让历史暴露完,再谈误报率。
我们的判断
无人值守系统里,故障的最小可见单位不是日志里的某一行,而是“预期与实际”的差集。日志要靠人去看,差集会被一个任务自己算出来。这一条决定了系统能不能在没有人值夜班的时候被发现。
推论一:如果一个团队的告警全部由任务产出触发,那么这个团队每新增一个任务,就多一份静默风险,因为通知是任务的可选属性。推论二:如果告警从一张计划表派生,新增任务只是新增一行预期,漏配的概率就变成了“忘了加计划”,而这件事可以被对账本身发现。
推论三反直觉。静默本身是正确设计,巡检任务不该天天吵人。问题不在于静默,在于静默把一个红色状态吞掉了。两件不相关的事被同一个开关控制,这是设计的错,不是值班的错。把开关拆成两个,一个管“平时要不要说话”,一个管“红了要不要说话”,机制上就修完了。
三个动作
第一,今天去看事故表里 alerted_at 为空、状态还是 detected 的行有多少条,最老的一条停了多久。这个数就是你的静默存量,它通常比估计的大。
第二,把计划写成数据,任务、节奏、最晚产出时间三列。哪怕只有一张 CSV,对账任务就有东西可比,差集才有定义。
第三,给产物模板加上提示词与结果的显式分隔。这一条和告警无关,但它决定了下一次排查时你能不能扫到真正的错误行。
留给值班的人一个问题:上一次你被一条失败通知叫醒,是什么时候。如果答不上来,系统现在可能正红着,只是没有人知道。
参考来源
内部数字来自我们自己的任务输出与事故表,统计窗口为 2026 年 11 月 12 日 18:00 至 11 月 13 日 18:22。外部机制参考 Prometheus 的缺席检测函数文档。
Prometheus 查询函数文档:absent 与 absent_over_time 用于在指标名和标签组合完全不存在时告警
常见问题
为什么任务失败了却没有人收到通知+
因为通知挂在任务的“是否静默”属性上,属性一旦写成静默,此后所有红色状态都跟着不送达。事故表又把已入库当成已通知,告警时间字段为空没人查。
三十小时里漏了多少+
九百三十一次运行被标记静默不送达,其中七份输出含明确的 ERROR 或 FAIL 行,四起故障停在已检测未告警,最老的一张鉴权故障停了三十三天。
为什么加一条失败就通知的告警规则不够+
规则对指标有效,对无人值守的批处理无效,因为失败在那里表现为序列缺席而不是指标异常。缺席检测要求先定义预期,预期必须落成可查的数据。
预期应该存在哪里+
存在一张表里,三列就够:任务、节奏、最晚产出时间。对账任务拿计划与实际比,差集即故障。存在人脑子里的预期等于没有预期。
静默设计本身是不是错的+
不是。巡检任务不该天天吵人。错的是把“平时要不要说话”和“红了要不要说话”放在同一个开关上。拆成两个就修好了。
怎么知道送达链路还活着+
每天固定时间发一份对账摘要,零故障那天也发一行写明差集为空。一份准时到达的没有异常,比一份只在出事时到达的告警更可靠,因为后者无法自证。
拿你自己的执行日志跑一遍
交一份脱敏的近 30 天 agent 执行日志,48 小时内拿到八行表:八项技术项每项一行,每格带分子、分母和判据,缺口按是否要改 schema 排序。前三单 ¥8,000。
相关文章
AI 在部门内省钱,在部门之间卡住
近六千名高管里 69% 说公司在用 AI,十个人里九个报不出生产率变化。产出发生在部门内,损耗发生在交接处,而那里没有报表。
提交涨了三成,关闭的需求没多一件
700 多家公司引入编码智能体后,代码涨 30%、提交涨 20%,需求关闭率没有统计显著变化。产量记在提交上,回报结在关闭上。
FDE 战争东移:商品化的是部署,不是证明
09-10 一天三件事:Moonshot 组五家中国 SI 联合 FDE 团队、Palantir 把 Fujitsu 变成 Global FDE Partner、Sakana×SCSK×住友借约 10 万客户铺渠道。FDE 从自建军团变成可租通道——但装完后 agent 动作由谁独立核验,三个市场空白一致。
Agent 失败不在模型里,在 harness 里:monday.com 的生产护栏
monday.com 公开 feedAgent 生产案例(官方工程博客,09-09):失败模式不在模型里,在围绕模型的假设里——输入、运行边界、输出验证、反馈闭环。我们的判断:护栏管住几层,agent 就有几分生产可用;没有 schema 与上限的 agent 是赌局,不是工程。