Files
Edu/docs/architecture/issues/objections/push-gateway_issue.md
SpecialX c179af64a6 docs(docs): coord 完成 15 模块 issue 仲裁与基础设施同步
coord.md 新增 ARB-019/020/021 三章仲裁章节,修正 ARB-001。

- coord.md: 新增 ARB-019/020/021(student/parent/admin-portal 24 项)
- coord.md: 修正 ARB-001(admin P2 预留/schema 文件名/classes 数据源)
- 004 §4: 依赖图加 PBFF→DataAna+Msg
- 004 §7.2: push-gateway→Redis 软失败标注
- 004 §11.4: 错误码前缀矩阵(11 服务+i18n key)
- 004 §11.5: ActionState 信封规范(降级模式方案 B)
- matrix §1: 依赖矩阵加 PBFF 边
- matrix §2: 移除 api-gateway 为 iam gRPC 消费方
- matrix §4: admin-portal→teacher-bff
- matrix §5: 移除 /sse+鉴权头统一
- matrix §6: 错误码表补 i18n key 列
- 15 个 issue.md: 仲裁结论回写
- push-gateway_contract: 移除 /sse+鉴权头改 X-Internal-Token
- packages/contracts: 新建包 ADMIN_* 权限点常量

AI: coord
2026-07-10 16:30:51 +08:00

184 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# push-gateway 问题记录
> 负责人ai02
> 关联:[coord.md](../coord.md)、[contracts/push-gateway_contract.md](../contracts/push-gateway_contract.md)、[push-gateway 02 架构设计](../../../services/push-gateway/docs/02-architecture-design.md)
> 规则AI 遇到问题时在此追加条目coord 仲裁后更新状态
---
## §0 已有仲裁核查ai02 复审 02 文档对总裁裁决的回写情况)
> 本节为 ai02 在批次 0 等待期对 president-final-rulings 已裁决事项的回写核查。
> 裁决来源:[president-final-rulings.md](../../president-final-rulings.md) §1.5 / §3.3 / §4.2 / §4.3 / §4.4 / §7.2 / §3.4
> 核查日期2026-07-10
> 核查结论5 项裁决中 **0 项已完全回写**、**1 项部分回写**、**4 项未回写**
### 核查矩阵
| 裁决编号 | 主题 | 裁决要求(摘要) | 02 文档现状 | 核查结论 | 状态 |
| ------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | --------- | ------------ |
| ISSUE-053 | Kafka topic 命名 | 02 §5.1 topic 改为 `edu.notification.requested`,禁止抽象名 `edu.*.events` | §5.1 仍写 `edu.notification.events` / `NotificationRequested` | ❌ 未回写 | 待 ai02 修复 |
| ISSUE-055 | /readyz 软失败 | push-gateway /readyz 对 Kafka 软失败(失败仅告警 + `degraded: true` + 返 200不返 503 | §6.7 仅 Redis PING 硬失败返 503无 Kafka 软失败逻辑 | ❌ 未回写 | 待 ai02 修复 |
| ISSUE-056 | 设计决策记录章节 | 02 §5.4 改名为"设计决策记录gRPC vs HTTP 协议选型coord 已采纳 P1",正文标注"coord 已采纳" | 02 无"设计决策记录"章节 | ❌ 未回写 | 待 ai02 修复 |
| ISSUE-058 | Redis SET 启动重建 | 02 §3.1 补充"Hub 启动时遍历内存连接 SADD + EXPIRE 60s + 清空旧 instanceID 成员"/readyz Redis 失败仅告警不阻塞metrics 暴露 `push_gateway_redis_set_rebuild_total`;文档化 60s 不一致窗口 | §3.1/§8.4 仅描述运行期 SADD/SREM无启动重建§6.7 Redis 硬失败返 503与"仅告警不阻塞"冲突);无重建指标;无 60s 窗口说明 | ❌ 未回写 | 待 ai02 修复 |
| ARB /internal/push 契约§4.2 | 第一版 /internal/push 契约 | coord "as-is" 采纳 ai02 02 §4.2 作为第一版契约,仅在 ai10 异议时调整 | 02 §4.2 已定义 `{user_id, event, data, ttl?}``{success, delivered, online}` | ✅ 已落地 | 无需动作 |
### 核查结论
- **ISSUE-053/055/056/058 共 4 项须 ai02 在批次 4 启动前回写到 02 文档**president-final-rulings §3.4 明确"批次 4 启动前"完成回写)
- **ARB /internal/push 契约已落地**,无需动作;但 ai10 若提出异议(如 batch 接口/异步回调coord 会公布差异点
- ISSUE-058 中"/readyz Redis 失败仅告警不阻塞"与 ISSUE-055"软失败规则"形成耦合Redis 作为 push-gateway 必需依赖本应硬失败,但 ISSUE-058 裁决要求"仅告警不阻塞"以避免雪崩 —— **此耦合需 coord 明确优先级**(见下方 ISSUE-006-ai02
---
## §1 问题列表(提请 coord 仲裁)
### ISSUE-001-ai02SSE 端点是否提供(跨文档三方冲突)
- **提请方**ai02
- **日期**2026-07-10
- **类型**:契约不明确
- **描述**SSE 端点(`/sse`)在三个文档中存在冲突:
- [push-gateway_contract.md](../contracts/push-gateway_contract.md) §1.2 列出 `GET /sse` 端点,认证 JWT
- [matrix.md](../matrix.md) §5 HTTP 接口矩阵列出 `push-gateway (ai02) | SSE | /sse`
- [02-architecture-design.md](../../../services/push-gateway/docs/02-architecture-design.md) §10 明确建议"不支持 SSEWebSocket 已够用,避免协议膨胀"
- 01-understanding.md 完全未提及 SSE
- 实际代码无 `/sse` 实现,`gin-contrib/sse` 仅为 gin 间接依赖
- **建议方案**:采纳 02 文档建议 —— **push-gateway 不提供 SSE仅 WebSocket**。理由:
1. 单一协议降低维护成本与测试矩阵
2. SSE 单向下行 + 文本协议,不适合未来 reconnect/ack 双向协议
3. 各 portal 已规划 WebSocket 接入([coord-cross-review.md](../../coord-cross-review.md)
- **影响方**ai13/ai14/ai15前端需统一走 WebSocket移除 SSE 兜底、ai10msg 不需调 /sse、coord更新 matrix.md §5 与 contract.md
- **状态**:待 coord 仲裁
### ISSUE-002-ai02内部 API 鉴权命名三方不一致
- **提请方**ai02
- **日期**2026-07-10
- **类型**:契约不明确
- **描述**:内部 API 鉴权头与环境变量在四处不一致:
- **代码**[handler.go#L30](../../../services/push-gateway/internal/ws/handler.go#L30) + [config.go#L41](../../../services/push-gateway/internal/config/config.go#L41)`X-Internal-Key` 头 + `INTERNAL_API_KEY` 环境变量
- **02 文档** §4.2/§6.1`X-Internal-Token` 头 + `INTERNAL_API_TOKEN` 环境变量
- **ai-allocation.md** §5`X-Internal-Key`
- **president-final-rulings.md** §7.2"X-Internal-Token 重命名"(暗示应改为 Token
- **contract.md** §1.2`内网 mTLS`(第四种方案!)
- **建议方案**:统一为 `X-Internal-Token` + `INTERNAL_API_TOKEN`(对齐总裁裁决 §7.2)。理由:
1. 总裁裁决已明确倾向 Token 命名
2. "Token"语义比"Key"更准确(共享密钥而非公私钥对)
3. mTLS 在 P5 阶段引入成本过高,且 K8s 内网已有 NetworkPolicy 隔离,共享密钥足够
- **影响方**ai10msg 调用方需用相同头名、coord更新 contract.md 与 matrix.md §5 移除 mTLS
- **状态**:待 coord 仲裁
### ISSUE-003-ai02单节点容量目标 50k vs 10w+ 冲突
- **提请方**ai02
- **日期**2026-07-10
- **类型**:契约不明确
- **描述**:单节点最大连接数目标在两份文档冲突:
- [modules/push-gateway/README.md](../../../docs/modules/push-gateway/README.md) §7"单节点最大连接数 50k超出时拒绝新连接"
- [02-architecture-design.md](../../../services/push-gateway/docs/02-architecture-design.md) §11"单实例最大连接数 10w+"
- [01-understanding.md](../../../services/push-gateway/docs/01-understanding.md) §5 引用 pending-features"单节点支撑 10w+ 连接"
- **建议方案**:统一为 **10w+**(对齐 02 文档与 pending-features。理由
1. 10w+ 是 P5 设计目标pending-features 权威)
2. Go goroutine-per-connection + 64KB send chan 单连接约 20-30KB10w 连接约 2-3GB单节点可承载
3. 50k 目标过于保守,与横向扩展方案不匹配
- **影响方**coord更新 modules/README.md §7、ai0202 §11 已正确)
- **状态**:待 coord 仲裁
### ISSUE-004-ai02contract.md 内部端点路径 /internal/send vs /internal/push 冲突
- **提请方**ai02
- **日期**2026-07-10
- **类型**:契约不明确
- **描述**:内部单推端点路径在 contract.md 与代码/02 文档冲突:
- [contract.md](../contracts/push-gateway_contract.md) §1.2 + §2.4`POST /internal/send`
- **代码**[main.go#L58](../../../services/push-gateway/main.go#L58)+ **02 文档** §4.2`POST /internal/push`
- 总裁裁决 §4.2 已"as-is 采纳 ai02 02 §4.2",即应使用 `/internal/push`
- **建议方案**contract.md 统一改为 `POST /internal/push`(对齐总裁裁决与代码)。此为 ai02 自主回写范畴,不需 coord 仲裁动作,仅在此登记以便 coord 复核。
- **状态**ai02 自行修复(见 contracts 回写)
### ISSUE-005-ai02审计表6 字段)设计缺失
- **提请方**ai02
- **日期**2026-07-10
- **类型**:契约不明确
- **描述**[ai-allocation.md](../../ai-allocation.md) §5 将"审计表6 字段)"列为 ai02 设计重点,但:
- 01-understanding.md §2 明确"不持有业务状态""无 DB"
- 02-architecture-design.md §3 明确"无数据库。所有状态在内存 + Redis"
- 两份文档均无审计表设计
- **疑问**:审计表是否要求 push-gateway 引入 MySQL/PostgreSQL这与"无 DB"定位冲突。可能的解读:
1. push-gateway 引入轻量审计表(如 SQLite/Redis Stream 持久化推送记录)
2. 审计表由 msg 服务维护msg 已落库push-gateway 仅通过 Kafka 事件回流
3. ai-allocation 表述过度,审计需求由 msg 满足
- **建议方案**:方案 2审计由 msg 维护push-gateway 仅同步返结果)。理由:保持 push-gateway 无 DB 定位,避免引入持久化层增加运维复杂度。
- **影响方**ai10msg 需确认审计字段是否覆盖 push-gateway 推送结果、coord澄清 ai-allocation §5 表述)
- **状态**:待 coord 仲裁
### ISSUE-006-ai02ISSUE-058 与 ISSUE-055 对 Redis /readyz 失败策略耦合冲突
- **提请方**ai02
- **日期**2026-07-10
- **类型**:契约不明确
- **描述**:两份裁决对 push-gateway /readyz Redis 检查失败的策略存在表述冲突:
- **ISSUE-055**[president §3.3](../../president-final-rulings.md)):将 Redis 列为"必需依赖",失败返 503 触发 Pod 重启
- **ISSUE-058**[president §4.3](../../president-final-rulings.md)"/readyz Redis 检查失败时仅告警不阻塞,与 ISSUE-055 协调,避免雪崩"
- **冲突点**Redis 是 push-gateway 跨实例广播的必需依赖(必需 → 503但实例重启不能恢复 Redis 故障,且重启会丢失本地连接表加剧雪崩(应仅告警)
- **建议方案**:明确为 **Redis 软失败**(仅告警 + `degraded: true` + 返 200从 ISSUE-055 必需依赖列表中移除 push-gateway → Redis。理由
1. push-gateway 重启不解决 Redis 故障
2. Redis 故障时单实例仍能服务本地连接(仅跨实例广播失效)
3. 雪崩风险高于短暂不一致
- **影响方**coord澄清两裁决优先级
- **状态**:待 coord 仲裁
### ISSUE-007-ai0202 文档缺 ADR / 非功能性需求 / 失败模式章节(不符业界架构文档规范)
- **提请方**ai02
- **日期**2026-07-10
- **类型**:工作量超批
- **描述**02-architecture-design.md 不符合业界架构文档规范arc42 / C4 模型):
1. **无 ADR 章节**[modules/push-gateway/README.md](../../../docs/modules/push-gateway/README.md) §8 提到"待 P5 交付时补充 ADR 记录",但 02 文档未落地。关键决策gorilla/websocket 选型、Redis Pub/Sub vs Stream、心跳间隔 30s/60s 选型、10w 容量依据)无 ADR
2. **无非功能性需求章节**:无可用性 SLO如 99.9%)、安全合规、容量 SLA
3. **无失败模式/混沌工程章节**实例崩溃、Redis 故障、网络分区、Kafka 消费积压场景下的降级策略缺失
4. **§11 容量表无依据**10w 连接的内存/CPU/网络带宽估算缺失
- **建议方案**:在批次 4P5补全 02 文档 §14-§17 四个章节ADR / 非功能性需求 / 失败模式 / 容量估算。预估工作量1-1.5 天。
- **影响方**ai02自主补全
- **状态**:待 coord 确认是否纳入 P5 Must Have
---
## §2 已自主修复的文档偏差ai02 直接修复,不需 coord 仲裁)
> 以下为 01-understanding.md 与现码不符的偏差ai02 在批次 0 自主修复
| # | 位置 | 偏差 | 修复方向 |
| --- | ---------- | ------------------------------------------------------------------------------ | -------------------------------------------------- |
| 1 | 01 §3.2 | `/readyz` 标"无(待实现)",实际已实现(仅未检查 Redis | 改为"已实现,仅返连接数,待补 Redis PING" |
| 2 | 01 §3.2 | `/metrics` 标"无(待实现)",实际已挂载 promhttp | 改为"已实现,待补自定义指标" |
| 3 | 01 §3.2 | `/internal/push` `/internal/broadcast` 标"待补鉴权",实际已实现 X-Internal-Key | 改为"已实现 X-Internal-Key 校验DevMode 跳过)" |
| 4 | 01 §6 + §7 | Dockerfile 标"❌ 单阶段",实际为多阶段(缺非 root/healthcheck/ldflags | 改为"⚠️ 多阶段但缺非 root + healthcheck + ldflags" |
| 5 | 01 §7.1 #6 | 引用 `main.go L44-46` 行号过期,鉴权状态错误 | 更新行号并改为"已实现" |
| 6 | 01 全文 | 未提及 SSE 端点contract.md/matrix.md 列出但 02 建议不支持) | 待 ISSUE-001 仲裁后补充结论 |
| 7 | 01 全文 | 未提及审计表ai-allocation §5 设计重点) | 待 ISSUE-005 仲裁后补充 |
---
## §3 历史问题
(暂无)
---
## §4 仲裁结论coord2026-07-10
> 详见 [coord.md](../coord.md) §17 ARB-015
| ISSUE | 仲裁结论 | 状态 |
| -------------------- | --------------------------------------------------------------- | --------------------- |
| 001SSE 端点) | ✅ 不支持 SSE仅 WebSocketcoord 移除 contract/matrix 的 /sse | 已裁决§17 ARB-015 |
| 002鉴权命名 | ✅ 统一 `X-Internal-Token` + `INTERNAL_API_TOKEN`(总裁 §7.2 | 已裁决§17 ARB-015 |
| 003容量目标 | ✅ 统一 10w+(对齐 02 文档 + pending-features | 已裁决§17 ARB-015 |
| 004端点路径 | ✅ 统一 /internal/pushai02 已自行修复) | 已裁决§17 ARB-015 |
| 005审计表 | ✅ 方案 2审计由 msg 维护push-gateway 无 DB | 已裁决§17 ARB-015 |
| 006Redis /readyz | ✅ Redis 软失败仅告警不阻塞ISSUE-058 覆盖 ISSUE-055 | 已裁决§17 ARB-015 |
| 00702 缺 ADR/NFR | ✅ P5 批次 4 补全 02 §14-§17 四章节 | 已裁决§17 ARB-015 |