NEW

免费试用已开放

立即开始

自动化 · 回调 · Webhook

企业微信自动化的失效与回退

更新于 2026-08-168 分钟

自动化上线那天所有人关心的是它跑起来的样子,很少有人问它停下来那天会是什么样。而这条链路一定会停 —— 账号掉线、依赖超时、规则配错、上游给了脏数据。真正决定损失大小的不是恢复速度,是停摆的那几个小时里人能不能接住原本由系统做的事。这篇讲三种失效形态各自该怎么接、降级为什么是四档而不是一个开关、恢复之后积压的动作按什么标准取舍。接入侧按 wecomapi 的形态来写,判断本身与走哪条路线无关。

失效有三种形态,只有一种好办

「企业微信自动化失败」在监控图上是一种样子,在业务侧是三种处境,人接手的方式完全不同。把它们混成一件事,是降级预案做了等于没做的根本原因。

  • 停摆:什么都不做了。看得见、影响可算、人接手的起点明确 —— 这是最好的一种,虽然它在告警群里最吵。
  • 半通:一部分动作成功了,一部分没有,而且没有清晰的边界。这是最难接的一种,因为人不知道该从哪一条开始补,多数人只能从头再来一遍,于是造出重复触达。
  • 乱来:系统在正常执行,只是执行的是错的。规则配错、变量取错、名单圈错都算。它最贵,因为人接手之前得先做撤销,而已经发出去的消息撤不干净。

绝大多数团队的预案只覆盖第一种:加一条掉线告警,人工顶上。但衡量一套降级设计好不好,该看后两种 —— 半通时能不能给出一份准确的「还差哪些没做」,乱来时能不能在一分钟内让它停下,并列出已经做过什么。这两个问题答不上来,恢复速度再快也只是把错误做得更快。三种形态还经常接连出现:一次半通拖久了会被人手工干预成乱来,乱来被发现之后又被紧急全停变成停摆。预案要覆盖形态之间的迁移,而不只是三个独立场景。

降级是四档,不是一个开关

「出事就关掉自动化」听着果断,实际是把全部工作量瞬间扔回给人,而人没有系统就不知道该做什么。可用的企业微信降级方案是一条梯度,每一档都还在提供价值,越往下人承担得越多、吞吐越低,但链路始终没断。

  1. 1全自动:系统执行,人事后抽检。正常状态。
  2. 2自动执行加延迟窗口:动作生成后先在队列里压一小段时间,窗口内运营可以逐条取消,到点才真正发出。对外动作一旦发出去就撤不干净,所以这一档买的是「发出去之前还有一次机会」,适合规则刚改完、还没建立信任的时候。
  3. 3人在环:系统把决策和上下文准备好,人点确认才执行。吞吐降一个数量级,但正确性由人兜底,适合怀疑规则有问题但还没定位到的时候。
  4. 4只出清单:系统不再执行任何动作,只输出「该给谁做什么」的待办,人手工完成。这是真正的底线,也是最容易被漏掉的一档。

三个约束比档位划分本身更重要。切档不能依赖发版,否则真出事的时候等不及。档位按业务链路切,不按整个系统切 —— 客户分配降到第三档的同时,内部状态同步完全可以留在第一档,一刀切只会让损失面凭空扩大。切回去时要能交代清楚人在低档期间已经做过什么,这一条直接决定恢复会不会造成第二次事故。

交接面:人要的是待办,不是日志

故障时工程师看到的是队列深度、错误率、重试次数;运营看到的是什么都没有。这个信息落差是降级失败最常见的原因 —— 系统明明完整保留着「哪些动作还没完成」,却只以工程语言存在,翻译成业务语言这件事在故障当天由人来做,通常做不完。

需要的是一个人可读的待办队列,把未完成的动作以业务语言吐出来:给谁、做什么、依据是什么、到什么时候就没有意义了。四项缺一不可,尤其是最后一项 —— 没有截止时间的待办,人会按列表顺序做,而列表顺序几乎总是错的。

实现上不必新建一套系统。把动作定义本身设计成自带业务描述字段,队列里每个待处理项就天然是一条待办;用 wecomapi 的事件回调驱动的那些动作同样落进这个队列,只是它们平时会被消费者立刻取走,队列看起来永远是空的。这一点很关键:这条通道平时就是活的、被用过的,而不是灾难当天第一次启用。

降级通道最常见的死法不是设计得不好,是从来没人用过。上线半年后打开一看,业务描述字段是空的、运营账号没配权限、页面在某次改版里被下掉了。

恢复之后,积压动作按保质期分类

系统恢复的那一刻,最危险的动作是「把积压的都追平」。积压里躺着的东西保质期完全不同,一起放出去比继续停着更糟:客户在同一分钟收到昨天的活动提醒、前天的跟进和今天的通知,观感上这不是恢复,是事故。

  • 必须补:状态同步、标签写入、对账修正这一类。它们晚了也要做,做完系统才回到一致状态。补的时候要限速,恢复初期链路本来就脆。
  • 过期即作废:时效性触达。昨天的活动提醒今天发出去不只是无效,是负资产,会直接抬高退订和删好友。
  • 要人判断:介于两者之间的,比如已经排队的客户跟进。数量通常不大,交给上一节那个待办队列,让人扫一眼决定。

重放的速率要比正常低一档,而且要先分清失败类型:用 wecomapi 的统一错误响应把容量类失败和参数类失败分开,前者退避后重来、后者直接进人工队列。不分开的后果是一批脏数据在重放时反复重试,把刚恢复的链路重新打死,而告警里全是同一条错误刷屏。

示意:动作定义自带保质期与恢复策略(自有结构,非接口字段)typescript
type Action = {
  id: string;
  kind: "sync_state" | "notify_customer" | "reconcile";
  // 人可读的一句话,故障时直接当待办展示
  humanDesc: string;
  // 过了这个时刻就没有业务意义
  expireAt: string | null;
  // 恢复后的处置,入队时就定好,不在恢复现场临时判断
  onRecover: "replay" | "drop_if_expired" | "handoff";
  // 三个终态等价:机器遇到终态一律跳过
  status: "pending" | "done_auto" | "done_manual" | "skipped_manual";
};

// 出口示意(端点与字段以线上接口文档为准)
// POST https://manager.wecomapi.com/message/sendText  { guid, toId, content }

人和机器必须共用一个状态机

降级期间人做过的事,恢复之后机器不能再做一遍。这句话听着是常识,但它对系统提出了一个具体要求:人工完成必须回写到和自动执行同一个状态字段上,而不是记在某个人的表格里或者某个群的聊天记录里。

典型事故的形状很固定 —— 自动化停摆,运营手工把该发的消息发了;两小时后系统恢复,队列里那批动作状态还是「待执行」,于是同一批客户收到第二遍,而这一遍看起来完全正常,没有任何告警。修它不需要复杂机制,只需要待办队列的每一项都有「标记为已人工处理」的入口,并且这个标记写的是同一个状态字段。

  • 人工处理也要留痕:谁在什么时候手工做的、做了什么。恢复后的对账全靠它,事后解释也全靠它。
  • 人工可以「跳过」,而跳过是一个终态,不是让动作回到待执行。回到待执行等于把它交还给机器,人的判断就白做了。
  • 冲突时以先到者为准。机器发现动作已是终态就静默跳过,不要覆盖、不要报错刷屏 —— 这类「冲突」在降级恢复期是常态而不是异常。

还有一种更隐蔽的重复来自粒度不齐:人一次性把一个群里该说的都说了,机器那边对应的是十条独立动作。如果界面只能整批标记、不能逐条标记,人要么全标要么不标,两种都会错。粒度对不齐的时候,宁可让人多点几下,也不要引入一个「批量标记为已处理」的近似 —— 它省下的几分钟,会在下一次对账时以小时计还回去。

演练,以及一个能这周就动手的版本

降级通道的可用性只能靠用来验证。一个成本很低的做法:每月挑一条链路,主动降一档跑一天。挑的时候选影响面小但流程完整的那条,目的是把权限、字段、人的操作习惯全过一遍,而不是测系统能不能扛住 —— 后者压测能做,前者只有真人操作一遍才知道。

  1. 1给每个动作补上保质期和恢复策略两个字段。投入最小、收益最直接,改动只落在定义层。
  2. 2把队列里的待处理项渲染成一个人看得懂的列表,先做只读版本。只读版本就已经能救一次事故。
  3. 3加上「标记为已人工处理」,让状态机对人开放。到这一步,恢复后的重复执行基本就绝迹了。
  4. 4完整的人在环审批界面放在末尾。多数团队做到第三步就够用很久,第四步该等到确实有一条链路需要长期跑在人在环档位时再做。

本文讲的是失效之后的组织方式。具体接口的错误语义、重试与幂等约定以 wecomapi 线上文档为准;降级档位怎么划要按你自己的业务损失模型来定,别照抄这里的四档。

常见问题

自动化出问题,直接全停是不是最安全的?
只有「乱来」这一种形态下全停是最优解,而且是临时的。停摆和半通两种情况下,全停等于把全部工作量瞬间扔给没有上下文的人,损失反而更大。更实用的做法是按链路降档:不可撤销的对外动作降到人在环或只出清单,内部状态同步这类可撤销的留在自动档。
降级期间的人工操作,怎么避免恢复后被重复执行?
让人工完成写回和自动执行同一个状态字段,「已人工完成」和「已自动完成」都是终态,机器恢复后遇到终态直接跳过。把人工操作记在表格或群聊里而不回写系统,是恢复后重复触达最常见的原因,而且这种重复不会触发任何告警。
积压的动作恢复后要不要全部补发?
按保质期分。状态同步、标签写入这类必须补,限速慢慢补;时效性触达过期就该作废;拿不准的交人工队列。这个分类要预先写在动作定义里,恢复现场没人有精力逐条判断。补完之后用 wecomapi 的事件回调或回读接口确认最终状态,别只信调用返回 —— 返回成功只说明请求被受理;没有对应事件可核的动作,就承认它只能停在「已提交」,在对账里单独盯着。

准备好动手了?

精确字段、鉴权与端点以线上文档为准;可在控制台创建密钥后联调。

相关文章