Files
orbit/docs/reports/phase-3-event-consumer-sdk.md

76 lines
6.1 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.
# P3 事件消费 SDK 与节点故障回归
验证日期:2026-09-17。已交付 [消费 SDK](../sdk/event-consumer.md) 和 [协议示例](../examples/event-protocol.md)。业务端持久化 Inbox 示例及消费者进程强杀恢复尚未完成,P3 和持续目标继续进行。
## 1. 实现范围
- [EventConnection](../../sdk/go/event_connection.go):严格事件协议、接收、请求关联、ACK、心跳和关闭;控制最多32个在途,接收缓冲为声明容量,超时关闭连接后保留原证明核对。
- [EventConsumer](../../sdk/go/event_consumer.go):自动心跳、指数退避重连、本地1–32个在途事件、成功后确认、ACK不明时原证明核对、处理器失败不确认、取消与有界收尾。
- [类型及秘密隐藏](../../sdk/go/event_types.go):ResultEvent不给业务处理器租约秘密;Grant/Proof仍可显式序列化用于受保护的存储,普通fmt隐藏敏感数据。
- [严格解码](../../sdk/go/event_codec.go):大小写、重复键、方向、会话、规范uint64、证明编码和事件/交付/快照关联。大整数不经float64转换。协议类WebSocket关闭按永久错误处理。
- [协议例子](../../examples/event-protocol/main.go):产生取消结果、读取、ACK、重连重报、验证原确认时间、暂停订阅。它只读取结果,不执行接收方业务写入。
- SDK保持独立模块,无新增数据库驱动、服务端包或持久化模型。本阶段不增加迁移、外键或级联删除。
## 2. 验证环境与入口
macOS、Go1.27.1、Docker MySQL8.4.10、一次性数据库;普通SDK集成连接真实Orbit进程,故障网关使用本地TLS,进程回归使用真实子进程和SIGKILL。注入后用Wait确认进程已经退出,不能以发送了Kill调用代替终止证据。
```sh
make fmt test vet build
make integration
cd sdk/go
GOWORK=off go test -race ./...
```
| 分组 | 结果 |
| --- | --- |
| 全量MySQL集成 | PASS,92.995秒 |
| SDK Worker连接/运行器 | PASS,88.494秒 |
| SDK计划、队列、订阅管理、应用配额 | PASS,5.704 / 4.466 / 33.386 / 1.363秒 |
| 新消费SDK三项集成 | PASS,2.18 / 15.28 / 33.14秒,包总计51.843秒 |
| 新节点交付租约恢复 | PASS,32.15秒 |
| 新ACK提交/丢响应/节点强杀 | PASS,1.31秒 |
| 九项真实进程故障(原七项加新两项) | PASS,包总计61.810秒 |
| 完整SDK示例 | 14个全部通过,包括新的event-protocol |
| fmt、race、vet、build | PASS |
| GOWORK=off独立SDK模块 | PASS,编译及竞态测试不依赖服务端workspace |
完整SDK示例输出包含:
```text
event=<本次事件ID> task=<本次任务ID> state=CANCELLED
ack_replayed=true same_receipt=true pending=0 subscription_enabled=false
```
## 3. 协议与运行器边界
[连接单元回归](../../sdk/go/event_connection_test.go) 在TLS服务器上混合投递与乱序控制响应,验证独立关联、精确数字、秘密隐藏;取消Next不关闭连接,已发ACK取消关闭连接并报告未知确认状态。32个控制槽满后拒绝新控制,交付缓冲满后关闭。拒绝重复键、大小写别名、非规范计数、null布尔/错误、缺失创建时间、错误事件关联、状态不匹配、额外字段及不匹配ACK;1008关闭不无限重连。
[运行器回归](../../sdk/go/event_consumer_test.go) 验证ACK回应丢失后原证明重连,不重复运行仍保留的已提交处理器;新代次替换后重新进入业务去重;error/panic/Goexit均不确认、不立即本地重试。取消后收集已提交结果,忽略取消的处理器在收尾期限到达后报告Running与Unconfirmed。永久401只连接一次,实例不能重复Run,容量2实际并行处理并限制并发。
处理器测试中的原子计数只用于确认调用次数,不能作为已实现持久化Inbox的证据。
## 4. 真实服务与MySQL
[三项SDK集成](../../sdk/go/event_integration_test.go):
1. 接收已取消任务的冻结快照,暂停后Ping返回enabled=false,已有Proof仍能ACK;关闭连接后重报返回同一确认时间。暂停时新增结果不投递,恢复后继续消费,最终pending_count=0。
2. 处理器持续等待真实15秒自动心跳,故障网关收到上游心跳ACK才放行业务完成。随后上游提交事件ACK,网关丢弃回应并断开。消费器重连核对原证明,处理器调用数和交付次数均保持1。
3. 首次处理器返回error,SDK不ACK。测试等待服务端真实30秒租约及退避,不修改数据库时间;同一交付以第二代次发送,处理成功后确认,最终attempts=2、HandlerFailures=1。
## 5. 真实节点强杀
[进程故障测试](../../sdk/go/event_process_integration_test.go):
- **领取提交后节点退出**:节点A成功投递后被SIGKILL并确认退出。节点B读取同一MySQL,在租约自然到期后恢复相同event_id/delivery_id,代次和次数增加到2。旧Proof返回DELIVERY_LEASE_LOST,新Proof成功ACK,订阅积压清零。
- **ACK提交后响应丢失**:网关截获成功ACK回应并阻断后续重连;通过查询确认ACKED和已保存的确认时间,然后强杀节点A。启动节点B,切换网关并恢复连接;Consumer仍持有原Proof,返回原确认时间,不新建交付尝试,不重跑处理器。
这两项强杀的是Orbit服务端进程。第二项消费器保持运行,其内存证明未丢失;不能将此证据当作消费者进程被强杀后业务去重也已验证。
## 6. 保留边界
- 后续需要交付独立业务数据库的Inbox事务例子,验证提交后/ACK前消费者进程退出、并发重复投递以及接收方事务回滚/提交不明等窗口,再验收P3可靠订阅。
- Consumer取消或传输断线不能撤销已经发出的业务效果;交付租约不是业务互斥锁。生产业务需要持久化唯一键和事务,外部副作用需要业务幂等/Outbox/核查。
- 当前仍按启用订阅的领取活动恢复过期交付;独立清扫、历史保留与清理、凭据安全重绑和生产容量/RPO/RTO仍属后续阶段。
- 结果证明只覆盖本报告的单数据库、进程/TLS网关拓扑;未将本机回归等同于百万租户容量或生产高可用验收。