跳到主要内容

试跑成功但生产执行失败

试跑成功而线上失败,差别在事件和进程:真实事件可能缺标签,线上执行的是告警进程而非页面进程,权限和网络可达性都不同。

工作流的试跑面板一片绿,每个节点都有输出,标签也改对了。挂到规则上,真实事件来了, 什么都没发生——执行记录空的,或者有记录但结果和试跑完全不一样。

紧急程度看这条工作流拦的是什么:只是补标签、发回调,可以慢慢查; 里面有丢弃处理器,那它现在可能正在吞掉真实告警,先把那条规则上的工作流引用禁掉再排查。

先分清是「没跑」还是「跑了但结果不对」​

工作流 → 执行记录,把时间范围拉宽(默认只有 6 小时),按事件 ID 或工作流名搜。 这一步把问题劈成两半,后面查的地方完全不同:

执行记录结论
一条都没有事件根本没进这条工作流——看下面「生效范围」和「有没有挂上」
有记录,状态 Success,消息 workflow terminated at node X跑了,事件在某个节点被丢弃了。这是正常结束,不是错误
有记录,状态 Failed跑了,某个节点报错了,详情里的「失败节点」写着是哪个
有记录,节点结果和试跑不一样跑了,但事件内容和你试跑时用的不一样——看下面「模拟事件缺了什么」

记录里的触发方式也要看一眼:事件触发 才是线上的那条路,API 触发 是试跑自己写的。 整条工作流试跑会写一条 API 触发 的记录,很容易被当成线上跑通了的证据。 单个处理器的试跑不写任何记录——它压根不走工作流引擎。

试跑和线上到底差在哪​

试跑接口在 Center 进程里,直接拿你传过去的配置执行;线上是告警引擎在事件产生时执行。 中间这几道关卡,试跑一道都不过:

关卡线上试跑
工作流有没有被规则引用没引用就永远不跑不检查,照跑
规则上那一项是不是启用的禁用的引用直接跳过不检查
工作流自己是不是禁用的禁用就跳过,日志 event pipeline is disabled不检查
生效范围(适用标签 / 适用属性)不匹配就整条跳过,日志 event pipeline not applicable不检查
配置从哪来数据库里已保存的那份请求体里编辑器当前的那份
工作流变量工作流上保存的值可以在对话框里临时覆盖
事件从哪来真实事件模拟事件,或你选的那条历史事件

最后三行是「试跑绿、线上红」的三个主要来源。

模拟事件缺了什么​

模拟事件由服务端凭空构造,只在内存里流转、不落库,哈希固定是 event-pipeline-test-mock-event。它带的东西就这些:

rulename=<工作流试跑样例事件>
__name__=cpu_usage_idle
ident=mock-host-01
env=prod
service=web

除此之外还有几个写死的字段,处理器如果按它们分支,试跑永远只能走到一个分支:

字段模拟事件里恒为真实事件里
数据源类型prometheus规则实际用的那种
业务组Default Busi Group规则所属的业务组
注解($event.AnnotationsJSON)空字典规则里配的 summary、description 等
关联对象($event.TargetIdent)空有主机的规则会带 ident
触发值6.70真实的查询结果
级别 / 是否恢复对话框里可调,默认告警、级别 2事件本身决定

所以下面这几种处理器配置,试跑一定看不出问题:

  • 按 $event.AnnotationsJSON.summary 取值或分支的——模拟事件里它是空的;
  • 按业务组、按数据源类型过滤的——模拟事件里恒为那两个值;
  • 依赖 ident 去查主机标签做补全的——mock-host-01 这台机器在设备列表里不存在。

级别和是否恢复这两个必须两边都试。 丢弃处理器最常见的写法就是 {{ if eq $event.Severity 3 }}true{{ end }} 和 {{ if $event.IsRecovered }}true{{ end }}, 只用默认值试一次,等于只验了一半。

想避开这一整节,就用历史事件模式挑一条真事件——它是从历史事件表里读出来再转成当前事件的, 形状和线上一致。

常见根因与确认方法​

工作流没挂上,或者挂在了另一个挂载点​

工作流不会自己生效,必须被告警规则或通知规则引用。而且两个挂载点作用不同: 挂在告警规则上影响所有下游,挂在通知规则上只影响那一条通知规则的那一次发送。

怎么确认:执行记录里的触发来源这一列直接写着 告警规则 #id 还是 通知规则 #id。 一条 事件触发 的记录都没有,就是没挂上。日志里也能验,processor_by_ 后面跟的 就是 alert_rule 还是 notify_rule。

怎么修:回到规则表单把它加上。工作流编辑抽屉里那块「去挂载」的提示就是干这个用的。

生效范围把真实事件挡在门外​

这是「执行记录一条都没有」最常见的原因,而试跑完全不检查生效范围, 所以试跑一定看不出来。

怎么确认:日志里 grep pipeline_id:,这一行就是它:

INFO dispatch/dispatch.go:265 processor_by_notify_rule_id:1 pipeline_id:1, event pipeline not applicable, event: c1de73eaa86f790d868cde6cc4d5903b

怎么修:把真实事件的标签和工作流的适用标签逐项对比。条件之间是与的关系, 留空表示不限制;实在定位不了,先把过滤开关关掉,关掉时所有事件都进来, 确认能跑通之后再一条条加回去。

改完没保存就去试跑​

试跑执行的是请求体里的配置,也就是你编辑器里当前的内容;线上执行的是数据库里存的那份。 所以「改一版、试跑一次、觉得对了就关掉抽屉」这个操作顺序,会留下一个从未保存的版本。

怎么确认:重新打开这个工作流,看处理器配置是不是你试跑时的那一版。 执行记录详情里的输入变量快照也能对——它记的是那一次真实执行用的值。

怎么修:保存,再看下一条真实事件的执行记录。

目标地址从告警进程访问不通​

回调和事件更新这两类处理器要发 HTTP 请求。试跑是 Center 进程发的,线上是告警引擎发的。 单进程部署时两者是同一个进程,没有差别;但拆出 n9e-alert、或者规则跑在 n9e-edge 上时, 发请求的是另一台机器,网络策略、DNS、证书都可能不一样。

怎么确认:执行记录里那个节点的消息就是对端的返回。到真正执行这条规则的那台机器上 手动 curl 一次目标地址,和记录里的结果对比。规则跑在哪个实例上,看 系统配置 → 告警引擎。

怎么修:按告警引擎所在的网络位置开通策略,别按浏览器或 Center 的位置开通。

执行记录写着 success,但事件被丢了​

丢弃是配置出来的正常行为,所以整体状态仍然是 Success,消息是 workflow terminated at node <节点名>,只有真正 Failed 的记录才会把消息标红。 被丢弃的节点之后没有任何节点结果——后面的处理器根本没跑。

怎么确认:打开这条记录,看节点执行结果里最后一个节点是不是丢弃处理器, 它的消息是「条件命中,事件已被丢弃」还是「条件未命中,事件继续下发」。

怎么修:如果这不是你想要的,改丢弃条件;如果是调试期间挡住了后面的节点, 把丢弃处理器往后挪——它一旦命中,后面处理器的输出你就再也看不到了。

确认修好了​

  1. 保存工作流,把它挂到规则上,确认规则上那一项是启用状态;
  2. 等一条真实事件,或者用规则的测试触发造一条;
  3. 回到工作流 → 执行记录,时间范围拉宽,确认出现了一条**触发方式为「事件触发」**的记录 ——这是唯一能证明线上链路通了的证据,API 触发 不算;
  4. 打开这条记录,逐个节点核对结果,尤其是标签改写节点的前后 diff;
  5. 有回调节点的,再去对端确认真的收到了。

收集这些再去提问​

  1. 工作流的完整配置(处理器类型、顺序、生效范围、变量),以及它挂在哪条规则上;
  2. 试跑的结果截图,和同一条事件的线上执行记录,两份一起给;
  3. 触发方式、状态、执行消息、失败节点这四项;
  4. 日志里这条事件哈希对应的 processor_by_ 行;
  5. 部署形态:单进程,还是拆了 n9e-alert,还是规则跑在 n9e-edge 上。

脱敏:回调地址、请求头里的 token、变量快照里的密钥一律替换; 标签的键名要保留,判定就是靠它们。

下一步​