forked from erp-dev/erp
166 lines
4.4 KiB
Markdown
166 lines
4.4 KiB
Markdown
# Notifier 模块实现说明
|
||
|
||
本文档面向后端维护者,描述 `notifier` 模块当前的实现决策、已落地范围与后续扩展注意事项。
|
||
|
||
## 1. 当前阶段
|
||
|
||
`notifier` 现已从第一阶段的“`Notifier` 直接绑定 `event_key`”升级为第二阶段的“`Notifier + NotifierRoute`”结构。
|
||
|
||
这样做的原因是:
|
||
|
||
- 一个通知器可能需要绑定多个事件
|
||
- 同一事件需要支持按任务分类路由
|
||
- 同一事件可能同时发往多个不同通知器
|
||
- 后续还可能出现更多路由维度
|
||
|
||
因此当前模块职责被拆成两层:
|
||
|
||
- `Notifier`:通知渠道配置、模板配置、启停控制
|
||
- `NotifierRoute`:事件匹配与业务路由规则
|
||
|
||
## 2. 当前范围
|
||
|
||
本阶段已实现:
|
||
|
||
- 独立 app:`notifier`
|
||
- Celery task 化投递
|
||
- 企业微信 webhook 渠道
|
||
- 模板化内容渲染
|
||
- Admin 可配置
|
||
- `NotifierRoute` 事件路由
|
||
- `mission` 相关事件按任务分类路由
|
||
|
||
本阶段仍未做:
|
||
|
||
- 旧模块静态通知逻辑迁移
|
||
- 外部 API
|
||
- 通知投递明细表
|
||
- 数据库级别审计
|
||
|
||
## 3. 核心模型
|
||
|
||
### 3.1 Notifier
|
||
|
||
- `config`
|
||
- `description`
|
||
|
||
当前 `Notifier` 已不再直接持有 `event_key`。
|
||
|
||
|
||
`NotifierRoute` 负责“何时发、发给谁”:
|
||
|
||
- `merchant`
|
||
- `notifier`
|
||
其中:
|
||
|
||
- `mission_category = null` 表示该事件的通配路由
|
||
|
||
- `Notifier` 在同商户下 `name` 唯一
|
||
- `NotifierRoute` 在同一 `notifier + event_key + mission_category` 下唯一
|
||
- `NotifierRoute` 额外限制同一 `notifier + event_key` 只能有一条通配路由
|
||
|
||
当前 `dispatch_notification_event(...)` 的匹配规则为:
|
||
|
||
1. 先按 `merchant + event_key + route.is_enabled=True + notifier.is_enabled=True` 查路由
|
||
- 也允许匹配通配路由
|
||
3. 如果 payload 中没有 `category_id`
|
||
- 只匹配通配路由
|
||
4. 如果同一个 `Notifier` 同时命中专用路由和通配路由
|
||
- 只保留一条
|
||
- 优先保留专用路由
|
||
|
||
- 同一通知器不重复发送
|
||
|
||
## 5. 当前调用链
|
||
|
||
通知链路如下:
|
||
|
||
1. `mission.services` 在事务提交后发 signal
|
||
## 6. 已接入的事件
|
||
|
||
当前 `mission` 已接入:
|
||
|
||
- `mission.unreplied`
|
||
- `mission.unreplied` 并非由业务 signal 直接触发,而是由后台每分钟一次的扫描任务按任务对象上的提醒配置触发
|
||
## 7. 日志策略
|
||
|
||
- 没有命中任何可用路由
|
||
- 路由命中成功
|
||
- backend 发送成功
|
||
- 单个通知发送失败
|
||
|
||
当前已增加 route 维度日志,重点字段包括:
|
||
|
||
- `event_key`
|
||
- `merchant_id`
|
||
- `route_id`
|
||
- `route_mission_category_id`
|
||
- `notifier_id`
|
||
|
||
## 8. Admin 现状
|
||
|
||
当前后台提供两个对象:
|
||
|
||
|
||
并且:
|
||
|
||
|
||
在 `Notifier` inline 场景下,route 的 `merchant` 会自动同步为当前 notifier 的商户,避免管理人员重复录入。
|
||
## 11. Mission 上的未回复提醒状态字段
|
||
|
||
当前未回复提醒的核心状态全部放在 `Mission` 对象自身:
|
||
|
||
- `notify_if_unreplied`
|
||
- `unreplied_notify_interval_minutes`
|
||
- `unreplied_notify_max_count`
|
||
- `unreplied_notify_sent_count`
|
||
- `unreplied_last_notified_at`
|
||
|
||
这样做的原因是:
|
||
|
||
- 配置和运行态统一放在任务对象上,最容易排查
|
||
- 不需要额外的提醒计划表或提醒历史表就能支撑当前需求
|
||
- 最大提醒次数和上次提醒时间都能直接在任务详情中观察到
|
||
这样旧配置不会因为结构调整而丢失。
|
||
|
||
## 10. 测试覆盖重点
|
||
|
||
当前测试已覆盖:
|
||
|
||
- 模板渲染
|
||
- backend 发送
|
||
- 路由按事件匹配
|
||
- 分类专用路由优先于通配路由
|
||
- 无专用路由时回退到通配路由
|
||
- 任务事件 handler 正常入队
|
||
|
||
## 11. 当前风险与注意点
|
||
|
||
### 11.1 当前只对 mission 做了分类路由
|
||
|
||
当前 `mission_category` 是显式写进 `NotifierRoute` 的业务字段。
|
||
这适合当前目标,但如果未来要扩展到其它业务模型的复杂路由,可能需要更抽象的路由条件模型。
|
||
|
||
### 11.2 config 仍是自由 JSON
|
||
|
||
后台录入错误仍可能在发送时才暴露。
|
||
当前依赖日志排查,后续可增加更强校验。
|
||
|
||
### 11.3 模板校验仍在发送期暴露
|
||
|
||
`template_key` 如果写错,会在渲染阶段报错并记录日志。
|
||
后续可在 admin 或 model clean 中增强校验。
|
||
|
||
## 12. 当前结论
|
||
|
||
当前 `notifier` 已具备:
|
||
|
||
- 通知器配置
|
||
- 路由配置
|
||
- 分类分发
|
||
- 任务事件按分类路由
|
||
- 管理后台操作支持
|
||
- 日志与测试保障
|
||
|
||
这已经足以支撑你当前提出的“所有任务事件都支持按任务分类路由”的要求。
|