试跑成功但生产执行失败
试跑成功而线上失败,差别在事件和进程:真实事件可能缺标签,线上执行的是告警进程而非页面进程,权限和网络可达性都不同。
工作流的试跑面板一片绿,每个节点都有输出,标签也改对了。挂到规则上,真实事件来了, 什么都没发生——执行记录空的,或者有记录但结果和试跑完全不一样。
紧急程度看这条工作流拦的是什么:只是补标签、发回调,可以慢慢查; 里面有丢弃处理器,那它现在可能正在吞掉真实告警,先把那条规则上的工作流引用禁掉再排查。
先分清是「没跑」还是「跑了但结果不对」
工作流 → 执行记录,把时间范围拉宽(默认只有 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 的记录才会把消息标红。
被丢弃的节点之后没有任何节点结果——后面的处理器根本没跑。
怎么确认:打开这条记录,看节点执行结果里最后一个节点是不是丢弃处理器, 它的消息是「条件命中,事件已被丢弃」还是「条件未命中,事件继续下发」。
怎么修:如果这不是你想要的,改丢弃条件;如果是调试期间挡住了后面的节点, 把丢弃处理器往后挪——它一旦命中,后面处理器的输出你就再也看不到了。
确认修好了
- 保存工作流,把它挂到规则上,确认规则上那一项是启用状态;
- 等一条真实事件,或者用规则的测试触发造一条;
- 回到工作流 → 执行记录,时间范围拉宽,确认出现了一条**触发方式为「事件触发」**的记录
——这是唯一能证明线上链路通了的证据,
API 触发不算; - 打开这条记录,逐个节点核对结果,尤其是标签改写节点的前后 diff;
- 有回调节点的,再去对端确认真的收到了。
收集这些再去提问
- 工作流的完整配置(处理器类型、顺序、生效范围、变量),以及它挂在哪条规则上;
- 试跑的结果截图,和同一条事件的线上执行记录,两份一起给;
- 触发方式、状态、执行消息、失败节点这四项;
- 日志里这条事件哈希对应的
processor_by_行; - 部署形态:单进程,还是拆了
n9e-alert,还是规则跑在n9e-edge上。
脱敏:回调地址、请求头里的 token、变量快照里的密钥一律替换; 标签的键名要保留,判定就是靠它们。
下一步
- 试跑面板怎么用:用模拟事件试跑
- 执行记录逐列怎么读:查看 Pipeline 执行记录
- 工作流怎么配:事件 Pipeline
- 跑通了但发错了地方:Pipeline 路由到了错误的目的地
- 标签改写的细节:改写标签与富化上下文