fix: correlate downstream receipts with submit responses

This commit is contained in:
hectorzhao
2026-07-14 16:22:41 +08:00
parent 135b4fd24e
commit 1ce02ef206
12 changed files with 487 additions and 91 deletions
+9
View File
@@ -1727,3 +1727,12 @@ git diff --check
- 功能提交 `8c03663f` 已 push 并部署生产。部署前 PostgreSQL 备份为 `/opt/cmpp-platform/backups/cmpp-20260714-142059.sql`(约 65MB),运行源码备份为 `/opt/cmpp-platform/backups/source-20260714-142059.tar.gz`(约 21MB);发布包本地和服务器 SHA-256 均为 `3e969aaf00e828da4167018bc349795413743414bc827d452859f0fd45776cd1`
- 生产 migration `20260714130000_add_downstream_delivery_ack_tracking` 成功应用,37 条 migration 全部齐全;历史 7 条 `delivered` 已按新口径迁移为 `unconfirmed`,204 个企业应用的回执和上行自动重试开关均为默认开启。生产 `.deployed-commit=8c03663f245c12cd5e6aab28ad9eeb68ea60ed57``cmpp-api``cmpp-gateway`、Nginx、MinIO 均 active`12026/17890/8090/3000` 监听,API/Gateway health、Redis、外部首页和运营端登录页均正常,部署后近期日志无新增 error;前端产物已确认包含“回执自动重试”和“客户端已确认”。未擅自发送或重投客户短信。
- 生产验证站点当前为 HTTP,已按发布约束显式设置 `SESSION_COOKIE_SECURE=false`,ACK 超时设置为 30 秒;无 Cookie 和无效 Cookie 访问受保护/会话接口均返回预期 401。服务器凭据文件对存量管理员只记录 `password=unchanged`,不是可用明文密码,因此未继续进行真实登录和开关点击,且已清除本次诊断产生的一次失败计数;登录后的页面交互由用户使用现有账号验收。
## 2026-07-14 下游回执 Msg_Id=0 与 SubmitResp 时序修复
- 生产核查 15:07、15:10 两条余额失败短信:`CmppDownstreamDelivery` 均记录 Result=0,但 ACK Msg_Id 都是 0Gateway 日志中的原 SubmitResp Msg_Id 分别为 `9677414932210841325``9687782471788644609`。这只能证明下游协议栈收到了 Deliver,不能证明下游平台已将状态回执关联到原短信,与下游页面仍显示“未回执”一致。
- 根因为 NestJS 在处理入站 Submit 时同步生成失败回执,而 Gateway 尚未建立 messageId 映射;原查找逻辑在精确消息未命中时回退账号会话,使用 bind 会话的零值 Msg_Id 提前写出 Deliver。上午 11:40 的回执手工重投后才显示,是因为重投时对应 Submit 映射已经存在,能携带正确 Msg_Id。
- 修复为:精确消息未登记时禁止回退账号会话;Gateway 仅在 ConnectResp/SubmitResp 成功写出后冲刷 pending;新建短信记录持久化原 CMPP Submit Sequence_Id,重启恢复时结合平台 MessageId 重建相同 Msg_Id;发送层拒绝任何 Msg_Id=0 的 DeliverNestJS 也不再把 Result=0/Msg_Id=0 标记为 delivered。
- migration `20260714153000_fix_downstream_receipt_message_id` 新增 `SmsMessageRecord.cmppSubmitSequenceId`,并把存量 `deliveryType=receipt/status=delivered/ackMessageId=0` 纠正为 `unconfirmed`,保留 ACK 证据但不冒充业务确认。
- 下游投递记录列表改为固定信息分组:投递类型/时间、企业/应用、消息 ID、状态、重试、最后错误和操作各自保持可读宽度,最后错误不再被挤成竖排。`delivered` 记录开放单条和批量手工重投,继续保留重复业务处理二次确认;`awaiting_ack` 仍禁止并发重投。
- 已新增 TC-GW-ACK-005 和 Gateway 回归:首个返回包必须是 SubmitResp,随后失败回执 Deliver Msg_Id 与 SubmitResp 完全相同;另覆盖精确映射不回退、持久化 Sequence_Id 恢复和 Msg_Id=0 拒绝。API 全量 15 suites、154 项、Gateway 全量 Go 测试、Prisma validate、真实本地 PostgreSQL migration、API build、前端 build 和 `git diff --check` 均通过;前端仅有既有 Vite chunk size warning。经用户授权在应用内浏览器完成一次本地图形验证码登录,使用真实 NestJS API、PostgreSQL 和临时投递记录在 1440×1000 视口验证列表无横向挤压、无 `NaN`、console 无 error/warn`delivered` 行的重投按钮可用且点击确实进入真实后端重投链路;因本地未运行 Gateway,请求按预期变为待重试而非伪造成功。临时投递记录和验收账号已清理。当前未提交、未推送、未部署生产。