# 有告警事件，为什么收不到通知？

有事件但没通知，先看通知记录：没有记录是被屏蔽规则或通知规则拦下，记录失败看媒介配置，记录成功但人没收到看对端。

最后校对于 2026-10-10

告警事件页上明明白白有一条事件，钉钉群、邮箱、手机都没动静。 这页顺着事件从产生到发出的**真实顺序**走一遍，每一步给出「怎么确认卡在这里」。

紧急程度按面判断：单条规则收不到，改规则就行；**所有规则都收不到**， 先去看通知媒介本身和 `n9e_alert_notify_record_queue_size` 有没有堆积。

## 先打开通知记录[​](#先打开通知记录 "先打开通知记录的直接链接")

**告警事件 → 打开这条事件 → 通知记录**。这是整页最省时间的一步： 有没有记录、记录是成功还是失败，直接把问题范围砍成三分之一。

| 你看到的                 | 卡在哪                                               |
| ------------------------ | ---------------------------------------------------- |
| 一条记录都没有           | 事件根本没走到通知这一步，看下面「没有任何通知记录」 |
| 有记录，状态是失败       | 走到了发送，发送本身出错，看「有记录但是失败的」     |
| 有记录，渠道显示「屏蔽」 | 命中了「只屏蔽通知」的屏蔽规则                       |
| 有记录，状态成功         | 夜莺这边发出去了，看「显示成功但人没收到」           |

记录里的**目标默认是脱敏的**（最后 8 位替换成星号）； 短信、语音、邮件、脚本和屏蔽这几类例外，显示原文。

通知记录默认只保留 **7 天**，每天凌晨 1 点清理。查历史事故要趁早。

## 链路的真实顺序[​](#链路的真实顺序 "链路的真实顺序的直接链接")

顺序错了就会查错地方。真实顺序是：

```
规则判定产生事件

      │

      ├─① 规则上挂的工作流（可以直接把事件丢掉）

      │

      ├─② 屏蔽规则

      │      · 屏蔽事件与通知（默认）→ 事件根本不产生

      │      · 只屏蔽通知           → 事件产生并落库，只是不发

      │

      ├─③ 落库；订阅规则在这里扩散出副本

      │

      └─④ 逐条通知规则：

            ├─ 通知规则上挂的工作流（第二个、独立的钩子）

            ├─ 按级别 / 标签 / 属性 / 时段匹配

            └─ 选媒介和消息模板，发送
```

两个最容易记反的地方：**工作流跑在屏蔽之前**；**工作流有两个挂载点**， 一个在告警规则上，一个在通知规则上。

## 没有任何通知记录[​](#没有任何通知记录 "没有任何通知记录的直接链接")

事件在，通知记录空的。按 ④ 里的顺序往回查：

**1. 这条规则挂通知规则了吗。** 规则详情里的「通知规则」为空，就没有任何东西会被触发。 这是新建规则最常见的遗漏，媒介测试和通知规则测试都测不出来它。

**2. 通知规则是启用的吗。** 禁用的通知规则会被**静默跳过**，日志里什么都不打。

**3. 是恢复事件、而恢复通知被关了吗。** 日志里会有：

```
notify_id: 1, event:<哈希>, should skip notify
```

**4. 通知规则上的工作流把事件丢了吗。** 这一种**会**留下一条失败的通知记录， 错误信息长这样：

```
processor_by_notify_rule_id:1 pipeline_id:3, drop by pipeline
```

而**告警规则上**的工作流丢弃事件时不写通知记录（那时候还没进入通知阶段）， 只在判定记录里留一个 `drop_by_pipeline` 阶段。

**5. 匹配条件把它过滤掉了。** 这是最常见的一种，而且**不写通知记录**，只写日志。 四种拒绝原因，措辞固定，直接 grep：

```
event time not match time filter

event severity not match severity filter

event tag not match tag filter

event attributes not match attributes filter
```

**特别注意级别**：通知配置里**一个级别都不勾，等于永远不匹配**—— 它没有「不填即全选」的语义。这条规则漏掉的通知，界面上看不出任何异常。

匹配成功时也有一行，可以用来确认确实走到了这一步：

```
notify send timeMatch:true severityMatch:true tagMatch:true attributesMatch:true event:<哈希> notify_config:...
```

**6. 改完配置多久生效。** 通知规则、消息模板、媒介的缓存都是 **9 秒**刷新一次， 改完立刻测有可能还在用旧的。

## 有通知记录，但是失败的[​](#有通知记录但是失败的 "有通知记录，但是失败的的直接链接")

记录里的详情就是原因，照着对：

| 详情                                           | 含义                                                                                                          |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `notify_channel not found`                     | 媒介被删了、或者被禁用了                                                                                      |
| `message_template not found`                   | 这条通知配置没选消息模板                                                                                      |
| `failed to enqueue notify task, queue is full` | 这个媒介的发送队列满了（每媒介 10 万条），下游卡住了                                                          |
| `all retries failed, last error: ...`          | 连都连不上，是网络或地址问题                                                                                  |
| `status_code:400, response:...`                | 对方收到了但拒绝了内容——一般是 token、签名或消息格式                                                          |
| `failed to execute template: ...`              | 模板渲染失败，见 [通知模板为什么渲染失败？](https://n9e.github.io/zh/docs/troubleshooting/template-errors.md) |

关于 `message_template not found` 有一个例外要知道： **callback、flashduty、pagerduty 这三类不消费消息模板**，缺模板不会被拦； 其余媒介缺模板会**整条丢弃并写一条失败记录**。 注意 callback 是按媒介标识 `callback` 放行的，你自己复制一份改了标识的 callback 媒介 **不在豁免之列**。

## 通知记录显示成功，人却没收到[​](#通知记录显示成功人却没收到 "通知记录显示成功，人却没收到的直接链接")

这一段最反直觉，但恰恰是最常见的报障。

**HTTP 类媒介只把「HTTP 200」算成功，而且完全不看响应体。** 钉钉返回 200 + `{"errcode":310000,"errmsg":"keywords not in content"}` 这种， 在通知记录里是**成功**。所以第一件事是把记录里的 `response:` 那一段读完—— 答案通常就写在里面。

顺带两个也算成功、但含义不同的：**201 / 202 / 204 会被当成失败**（只认 200）； 而**只有传输层错误才重试**，任何一个 HTTP 响应都是一次就返回。

按媒介类型，还有几条各自的脾气：

* **FlashDuty**：不管对方返回什么状态码，**一律记成功**（这是刻意设计，避免重试打乱对端数据）。 只能靠记录里的响应体判断，`status_code:` 后面是几就是几。
* **PagerDuty**：200 和 202 算成功，其余状态码会重试，默认共 4 次。
* **邮件**：通知记录里渠道恒为 `Email`、成功时详情恒为字面量 `success`， **不是对方 SMTP 的响应**。而且**成功入队时不写记录**，只有真正发送失败才写； 更绕的一点是：第一次失败、重试成功的情况，记录里仍然是失败。 邮件要以收件箱为准，不要以记录为准。
* **企业微信带截图时**：文本和图片是两次请求，图片那次失败会让整条判失败。

如果记录里响应体也正常，就是对端的问题了：群机器人的关键词/IP 白名单、 邮件进了垃圾箱、手机号不在接收人列表里。用 **媒介的「测试」按钮**再发一条， 直接看对端有没有收到，能把边界划清楚。

## 订阅规则不会替你止损[​](#订阅规则不会替你止损 "订阅规则不会替你止损的直接链接")

订阅是**加一份通知**，从来不会减少原规则的通知。所以「订阅了但没收到」和 「原规则也没收到」是两个独立问题，各查各的。

一个容易踩的点：**订阅规则如果没有选通知规则，订阅出来的那份副本就不会走 v9 的通知链路**， 等于订阅了个寂寞。订阅产生的通知记录会归在事件详情的「订阅规则通知」那张表里。

## 收集这些再去提问[​](#收集这些再去提问 "收集这些再去提问的直接链接")

1. 事件 ID，以及通知记录的完整内容（记录里的目标已脱敏，可以直接给）；
2. 规则详情里「通知规则」这一项，和通知规则里每条通知配置的级别勾选、标签过滤、时段；
3. 日志里这一时刻的 `notify_id:`、`notify send timeMatch:`、`not match` 三类行；
4. `curl -s http://127.0.0.1:17000/metrics | grep n9e_alert_notify_record_queue_size`。

**脱敏**：webhook 地址、access token、签名密钥、手机号、邮箱一律替换； 响应体里的 `errmsg` 要保留（它就是答案）。

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

* 收到了但内容是报错文本：[通知模板为什么渲染失败？](https://n9e.github.io/zh/docs/troubleshooting/template-errors.md)
* 发给了错误的人：[Pipeline 为什么路由到了错误的目的地？](https://n9e.github.io/zh/docs/troubleshooting/wrong-routing.md)
* 事件本身就没产生：[查询有结果，为什么告警不触发？](https://n9e.github.io/zh/docs/troubleshooting/alert-not-firing.md)
* 链路的完整模型：[降噪与路由模型](https://n9e.github.io/zh/docs/concepts/noise-routing.md)
* 怎么端到端测一遍：[端到端测试一条通知](https://n9e.github.io/zh/docs/notifications/test.md)
