Commit cb303524 by luoqi

docs(push): 加 §6 可靠投递/异常/漏推 + checklist(回执看 envelope code、outbox、reconcile 补漏)

- §6.1 回执:统一 envelope {code,msg,data},HTTP 恒 200(崩溃才 5xx)→ 判成败看 body.code 非 HTTP;
  按 code 族判重试(1xxxx/30802 不重试告警;10003/9xxxx/5xx/超时 退避重试)。修正之前误用 HTTP 401/400 的表。
- §6.2 防丢:本地 outbox + 重试到确认 + 异步不阻塞业务 + 不确定也重试(幂等去重)。
- §6.3 漏推补齐:数仓兜底(reconcile,首选)/ 周期幂等补推(纯 push)/ PAC 侧检测告警。
- checklist 补 outbox / 按 code 判重试 / 周期补推 / amountUnit+timezone 配置。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
parent fb52cf5e
......@@ -116,11 +116,11 @@ POST /pac/v1/push/events
| `consultation` | `consultation_recorded` | `intentCategories[]` |
> **金额、时间按你系统原样发,不用自己转**:接入时配置 `amountUnit`(fen/yuan)+ `timezone`(IANA),
> PAC 自动归一成「整数分 + UTC」(同数仓口径)。金额带 `currency`;时间本地值即可(带 offset 也接受)
> PAC 自动归一成「整数分 + UTC」(同数仓口径)。金额带 `currency`;时间本地值即可。
---
## 4. 幂等 / 防重(两形态都保证,你只管两件事)
## 4. 幂等 / 防重
PAC **自己合成幂等键**(你**不发** `source_event_id`)。你只要:
1. **身份稳定**:有 `subjectId` 就给;没有,保证自然键稳定(诊断 = `emrId+name+tooth`);
......@@ -148,7 +148,47 @@ PAC 靠你**发事件**才知道——**物理删除永远感知不到**。所
---
## 6. 限制 / 约定
## 6. 可靠投递 / 异常 / 漏推(宿主侧)
### 6.1 回执:看 envelope `code`,**不是 HTTP 状态**
PAC 统一返回 `{ code, msg, data }`,**HTTP 恒 200**(只有进程级崩溃才 5xx)。判成败**看 `code`**:
| 场景 | HTTP | `code` | 重试? |
|---|---|---|---|
| 成功 | 200 | `0` | — `data`={syncLogId, accepted, transactionsWritten, duplicates, failed} |
| 验签失败(secret/时钟/签名)| 200 | `101xx`(如 10106)| ❌ |
| 字段校验失败 | 200 | `10002` | ❌ |
| 请求格式错 | 200 | `10001` | ❌ |
| 数据形态漂移(字段/结构对不上)| 200 | `30802` | ❌ |
| 限流 | 200 | `10003` | ✅ |
| PAC 内部错 | 200 | `9xxxx` | ✅ |
| PAC 崩溃 | **500** | `9xxxx` | ✅ |
| 超时 / 连不上 | — | — | ✅ |
> **规则**:`0` 成功;`1xxxx`(除 10003)/`30802` → **别重试,告警人工**(你侧问题:secret/字段/数据形态);`10003`/`9xxxx`/HTTP 5xx/超时 → **退避重试**。
> ⚠️ 只看 HTTP 200 会把"验签失败"当成功——**必须读 `body.code`**。
### 6.2 防丢:本地 outbox + 重试到确认(异步,不阻塞业务)
- 业务事务内:写业务表 **+** 写 outbox(payload+status,**同一事务**)→ PAC 再挂数据也不丢;
- 后台 worker:取 pending → 推 → `code=0` 置 done;`9xxxx/5xx/超时/10003` 退避重试(1s→5s→30s→2m→…封顶);`1xxxx`(非限流)/`30802` 置 failed + 告警;
- **不确定也重试**:发了没收到响应 → 直接重试,PAC 幂等去重,**绝不重复**
- PAC 挂 → outbox 堆积,**诊所照常看诊/收费**,绝不让推送失败阻塞业务。
### 6.3 漏推(整条没推上来)怎么补 —— reconcile
push 可能整条漏(宿主 bug / 没入队 / 崩溃没持久化)。三层兜底,核心是**幂等让你能随时重推补**:
1. **数仓兜底(首选,若你也进数仓)**:push 是快路径,PAC 的 Pull + 对账自动追平漏推(七层防线第 4 层)——丢了也补得回;
2. **周期幂等补推(纯 push)**:每晚把最近 N 天数据**全量重推一遍**——已推跳过、漏的补上、改的升版本。这就是 push 侧对账,定时无脑跑;
3. **PAC 侧检测**:push 量异常下降 / 某 host 太久没推 → PAC 告警 → 人工触发补推。
> **漏推不是灾难,补推一遍即可**(幂等,重推任意时间窗不重复)。根上少漏靠 §6.2 的 outbox 持久化。
---
## 7. 限制 / 约定
| 项 | 约定 |
|---|---|
......@@ -159,7 +199,7 @@ PAC 靠你**发事件**才知道——**物理删除永远感知不到**。所
---
## 7. 宿主接入 Checklist
## 8. 宿主接入 Checklist
- [ ] 拿到 PAC 分配的 `Host-Id` + `secret`
- [ ] 实现 HMAC 签名(`{ts}.{rawBody}`;同一串 body 签+发)
......@@ -167,7 +207,11 @@ PAC 靠你**发事件**才知道——**物理删除永远感知不到**。所
- [ ] 每条记录:身份稳定(有 `subjectId` 给,无则自然键稳定)、`updatedAt` 随内容变
- [ ] 多品牌每条带正确 `tenantId`
- [ ] 删除走软删 + `*_cancelled`
- [ ] 全程 HTTPS;失败重试
- [ ] 接入时配置 `amountUnit`(fen/yuan)+ `timezone`(IANA)
- [ ] 全程 HTTPS
- [ ] **本地 outbox 持久化 + 异步 worker**(业务写库与入队同事务;不 fire-and-forget)
- [ ] 失败/异常**按 `body.code` 族判重试**(非 HTTP 状态;见 §6.1)
- [ ] **周期幂等补推**最近 N 天(纯 push 宿主兜底漏推;若也进数仓则靠 PAC 对账)
---
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment