# 工作流试跑成功，为什么生产执行失败？

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

最后校对于 2026-10-10

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

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

## 先分清是「没跑」还是「跑了但结果不对」[​](#先分清是没跑还是跑了但结果不对 "先分清是「没跑」还是「跑了但结果不对」的直接链接")

**工作流 → 执行记录**，把时间范围拉宽（默认只有 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但事件被丢了 "执行记录写着 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、变量快照里的密钥一律替换； 标签的**键名要保留**，判定就是靠它们。

## 下一步[​](#下一步 "下一步的直接链接")

* 试跑面板怎么用：[用模拟事件试跑](https://n9e.github.io/zh/docs/events/try-workflow.md)
* 执行记录逐列怎么读：[查看 Pipeline 执行记录](https://n9e.github.io/zh/docs/events/execution-records.md)
* 工作流怎么配：[事件 Pipeline](https://n9e.github.io/zh/docs/events/pipelines.md)
* 跑通了但发错了地方：[Pipeline 为什么路由到了错误的目的地？](https://n9e.github.io/zh/docs/troubleshooting/wrong-routing.md)
* 标签改写的细节：[改写标签与富化上下文](https://n9e.github.io/zh/docs/events/relabel-enrich.md)
