# 重试与投递状态

通知发送失败只对「连不上」自动重试，参数按发送类型各不相同；每条消息的投递结果在通知记录里可查，记录保留 7 天。

最后校对于 2026-10-10

这页办完你会知道：一条通知从「决定要发」到「对方收到」中间可能卡在哪， 哪些失败会自动重试、哪些不会，以及事后去哪儿翻这一条到底发生了什么。

## 消息是怎么发出去的[​](#消息是怎么发出去的 "消息是怎么发出去的的直接链接")

发送路径按媒介的**发送类型**（`request_type`）分三条：

| 发送类型                                                         | 怎么发                       | 并发控制                                 |
| ---------------------------------------------------------------- | ---------------------------- | ---------------------------------------- |
| `http`（钉钉、企业微信、飞书卡片、Telegram、回调、自建 webhook） | 进这个媒介自己的队列，异步发 | 媒介上的**并发数**                       |
| `smtp`（邮件）                                                   | 同步发，走邮件连接池         | 媒介上的**批量发送**（一次连接里发几封） |
| `flashduty` / `pagerduty` / `script`                             | 直接调用，同步               | 无                                       |

HTTP 队列满的时候消息会被丢弃，并写一条失败记录： `failed to enqueue notify task, queue is full`。看到它说明目标端太慢或者并发数配得太小。

## 重试只覆盖「连不上」[​](#重试只覆盖连不上 "重试只覆盖「连不上」的直接链接")

这是最容易误解的一点。HTTP 媒介的重试循环是这样的：

* **请求根本发不出去**（DNS 解析失败、连接被拒、超时）→ 等一个**重试间隔**再来一次， 最多重试**重试次数**遍；全失败后写一条 `all retries failed, last error: <最后一次的错误>`。
* **对方返回了任何 HTTP 响应** → **立刻返回，不重试**。200 记成功，非 200 记失败， 记录里是 `status_code:<码>, response:<响应体>`。

也就是说，钉钉返回 400「关键词不匹配」、企业微信返回 45009「超频」， **都不会重试**。这是有意的：重发一条对方已经明确拒绝的消息没有意义， 而且对下游的去重不友好。

还有一个边界：**重试次数填 0 等于一条都不发**——循环体一次都不进， 记录里是一条 `all retries failed`，错误信息还是空的。别把它当限流开关用。

## 每种发送类型的重试参数不一样[​](#每种发送类型的重试参数不一样 "每种发送类型的重试参数不一样的直接链接")

| 参数         | `http`                           | `flashduty` / `pagerduty`             |
| ------------ | -------------------------------- | ------------------------------------- |
| 超时         | 超时时间（毫秒），内置媒介 10000 | 超时时间（毫秒），内置 FlashDuty 5000 |
| 重试次数     | 重试次数，内置媒介 3             | 重试次数，不填按 3                    |
| 重试间隔     | 重试间隔（毫秒），内置媒介 100   | 重试等待时间（毫秒），不填按 1000     |
| 实际尝试次数 | 等于重试次数                     | 重试次数 + 1                          |

新建媒介时表单给的默认值和内置媒介不完全一样（超时 10000、并发 3、重试 3、间隔 3000）， 按需要改。

对「对方回了个错误状态码」这件事，三条路径的态度也不一样：

* **`http`**：只有 200 算成功，其余状态码记失败，**但不重试**；
* **`pagerduty`**：200 和 202 算成功，**其余状态码会按重试次数再试一轮**；
* **`flashduty`**：只要请求发出去了就算成功，状态码只记录不判断——重发会破坏对方的去重。

## 发之前就被丢掉的几种情况[​](#发之前就被丢掉的几种情况 "发之前就被丢掉的几种情况的直接链接")

这几种情况下请求压根没发出去，但**通知记录里有一条失败记录**：

| 记录里的文字                                   | 原因                                                       | 怎么修                                                                                    |
| ---------------------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `message_template not found`                   | 这条通知配置没选消息模板                                   | 回通知规则补上模板。FlashDuty、PagerDuty 和「回调」类媒介不需要模板，界面上也不显示这一项 |
| `notify_channel not found`                     | 媒介被删了，**或者被停用了**——引擎侧的缓存只装启用中的媒介 | 把媒介启用回来，或换一个                                                                  |
| `failed to enqueue notify task, queue is full` | HTTP 发送队列满                                            | 提高媒介的并发数，或者查目标端为什么慢                                                    |

另外两种情况**连记录都不会有**，因为事件根本没走到通知这一步： 通知规则上挂的事件处理工作流把事件丢弃了，或者恢复事件遇上「不通知恢复」的规则。

## 在哪儿看送没送到[​](#在哪儿看送没送到 "在哪儿看送没送到的直接链接")

开源版没有独立的「通知记录」菜单页，记录挂在事件上： **告警通知 → 告警事件 → 点开一条事件 → 通知记录 → 查看详情**。

抽屉里分**告警规则通知**和**订阅规则通知**两张表，列是通知规则 ID、通知渠道、 通知对象、通知目标、通知状态。三点值得注意：

* **同一个（渠道 + 目标）的多条记录会被合并成一行**，状态取更差的那个， 说明文字拼接在一起。所以一行里可能同时看到成功和失败的片段。
* **通知目标默认打码**，末 8 位变成星号。只有邮件、短信、语音、脚本和屏蔽记录 显示完整值——这几类的目标本来就是收件人自己看得到的信息。
* 记录是异步入库的（内存队列每 100 毫秒批量落一次），刚发完立刻刷新可能还看不到。

状态有三种：**成功**、**失败**，以及**被屏蔽**——最后一种来自「只屏蔽通知」的屏蔽规则， 渠道显示成 `mute`，目标是 `id=<屏蔽规则 id>`，说明文字里带屏蔽规则的名字。 用它可以回答「这段时间到底屏蔽掉了什么」，详见[屏蔽规则](https://n9e.github.io/zh/docs/events/mute-rules.md)。

## 通知记录只留 7 天[​](#通知记录只留-7-天 "通知记录只留 7 天的直接链接")

`notification_record` 是持续高频写入的大表，中心端每天凌晨 1 点清理一次， **默认只保留 7 天**。想改保留天数，在中心端配置文件的 `[Center]` 段里加：

```
[Center]

# 通知记录保留天数，默认 7

CleanNotifyRecordDay = 30
```

要长期留存就自己往外导，不要靠加大这个值——这张表的写入量跟告警量成正比。

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

* 先验证通道再上线：[端到端测试一条通知](https://n9e.github.io/zh/docs/notifications/test.md)
* 消息内容渲染失败：[模板渲染报错](https://n9e.github.io/zh/docs/troubleshooting/template-errors.md)
* 一条都收不到时的排查顺序：[有告警事件，为什么收不到通知？](https://n9e.github.io/zh/docs/troubleshooting/no-notification.md)
