chore(push-gateway): ai02 module updates - config, hub, ws, kafka, health, docs

This commit is contained in:
SpecialX
2026-07-10 17:36:53 +08:00
parent dc0a6feec4
commit 3fac472a57
16 changed files with 2017 additions and 289 deletions

View File

@@ -364,14 +364,29 @@
### 2.8 push-gatewayGoP5
| 场景 | 技术/规则 |
| ---------------- | ---------------------------------------------------------------- |
| WebSocket 长连接 | 单节点支撑 10w+ 连接,业务服务只需调 /internal/push |
| 跨实例同步 | Redis PubSubRedisURL 配置,预留 P6 实现) |
| 离线消息 | 仅推在线用户,离线消息存 MySQL上线时拉取 |
| 并发写修复 | send chan + 单写协程模式,避免 gorilla/websocket 并发写竞争 |
| DEV_MODE 鉴权 | DEV_MODE=true 时接受 dev-token生产环境必须 JWT 校验 |
| 广播端点 | POST /internal/broadcastbody {event, data},调用 hub.Broadcast |
| 场景 | 技术/规则 |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| WebSocket 长连接 | 单实例支撑 10w+ 连接ISSUE-003,业务服务调 /internal/push 或消费 Kafka |
| 心跳协议 | RFC 6455 控制帧Ping/Pong30s 间隔SetReadDeadline(60s) 超时断开;禁止文本消息 ping/pong |
| 单用户连接数限制 | 默认 5超限返 PUSH_TOO_MANY_CONNECTIONS + close frame 1008 |
| 跨实例同步 | Redis Pub/Sub 订阅 `edu:push:channel:user:<userID>` + `edu:push:channel:broadcast`;在线 SET `edu:push:online:<userID>` 60s TTL |
| Redis SET 启动重建ISSUE-058 | 启动时 SREM 旧 instanceID 成员,基于内存连接 ForEachUser 重新 SADD避免 Pod 重启后残留幽灵在线状态 |
| 离线消息 | 仅推在线用户;离线消息落库由 msg 服务负责ISSUE-005push-gateway 无 DB |
| 并发写修复 | send chan + 单写协程模式,避免 gorilla/websocket 并发写竞争 |
| 内部 API 鉴权 | `X-Internal-Token` 头 + `INTERNAL_API_TOKEN` 环境变量ISSUE-002原名 X-Internal-Key 已废弃) |
| Kafka topic 命名ISSUE-053 | `edu.notification.requested`(非 edu.notification.events遵循 G16 `<domain>.<aggregate>.<action>` 规则) |
| Kafka 幂等性 | 基于 event_id Redis SETNX 去重24h TTLat-least-once + 消费失败 3 次入 DLQ |
| /readyz 软失败ISSUE-058/006 | Redis/Kafka 不可达返 200 + `degraded: true`,仅 Hub.CloseAll 触发 closing 时返 503避免 K8s 在依赖抖动时驱逐 Pod |
| 无 gRPCISSUE-007 | 仅 HTTP + WebSocket不暴露 gRPC 服务 |
| shared-go 复用ARB-015 §17.5 | tracer/logger/jwks/env 走 shared-go 包,不重复实现 |
| 错误码前缀 | `PUSH_*`PUSH_UNAUTHORIZED/PUSH_INVALID_REQUEST/PUSH_TOO_MANY_CONNECTIONS 等) |
| 多阶段 Dockerfile | golang:1.25-alpine 构建 → alpine:3.20 运行CGO_ENABLED=0 + ldflags -s -w + non-root user + wget healthcheck |
| slog 结构化日志 | log/slogJSON prod / text dev替代标准 log 包;字段含 request_id/trace_id/user_id/conn_id/event |
| DEV_MODE 鉴权 | DEV_MODE=true 时接受 dev-tokenHS256 fallback生产环境必须 JWT RS256JWKS 5min 缓存) |
| 广播端点 | POST /internal/broadcastbody {event, data},调用 hub.Broadcast |
| gorilla/websocket API 陷阱 | SetReadLimit 返回 void不可 `_ =` 赋值SetPongHandler 签名为 `func(appData string) error`(非 `func(string, error) error` |
| sync.RWMutex 重入死锁 | 持写锁Lock的 goroutine 不可再调用同结构体的 RLock 方法Go RWMutex 非重入CloseAll/Broadcast 内部计数改为内联遍历 |
| httptest.Server.Close() 死锁 | 测试 handler 阻塞 ReadMessage 时 Close() 会死锁;用 done channel 模式cleanup 先 close(done) → cli.Close() → srv.Close() |
### 2.9 ai-gatewayPython/FastAPIP5