文档:同步游玩计数关停不强制 flush 与失败丢弃口径

- ADR:修订「正常关停必须 force flush」为关停不做强制 flush,并补充 flush 任一分片失败即丢弃剩余分片;追加修订记录
- 玩法链路:缓冲与延迟改为崩溃/被杀/正常关停都允许丢一个窗口;限流节补充先做内存预检;写入语义补充失败丢弃口径
- decision-log:顶部新增 2026-10-04 修订条目,并给 2026-10-03 条目标注失效项
- docs/README:ADR 摘要去掉「关停 flush」
This commit is contained in:
2026-10-04 11:13:55 +08:00
parent 28ac8a1037
commit c0148dda7e
4 changed files with 27 additions and 10 deletions
@@ -43,8 +43,8 @@
### 4. api-server 纯内存缓冲 + 周期 flush
- **纯内存,不落盘**:崩溃/被杀允许丢最后一个 flush 窗口;正常 SIGTERM/滚动重启必须在
`finalize_shutdown` 内 force flush。
- **纯内存,不落盘**:崩溃、被杀和正常 SIGTERM/滚动重启都允许丢最后一个 flush 窗口;进程退出不做
force flush,关停路径不为计数等待网络(2026-10-04 修订,见「修订记录」)。
- **两张表**:增量表 `pending: HashMap<gameId, u64>`(5 秒级、flush 即清)与 30 分钟去重窗口表 `seen:
HashMap<identity + gameId, timestamp>`(30 分钟级、按 TTL 清理)。两者键不同、生命周期差 360 倍,不能合并:
合并会把 30 分钟窗口状态塞进 5 秒清空的表,或让 flush 需要按 gameId 重新聚合。
@@ -64,6 +64,9 @@
丢量。理由是:超时后重试会在"其实已提交"时造成系统性双计,而丢弃只是偶发少计——对一个非交易展示指标,
后者更可接受(perf 优先于 correctness)。
一次 flush 按 500 分块;任一分片失败即终止本次 flush 的后续分片,剩余增量直接丢弃(`Build` 只把当前分片
放回)。连接不通时剩余分片只会重复同样的失败,逐个重试会把 worker 卡在多次连接超时上(2026-10-04 补充)。
### 7. 接口
`POST /api/game-distribution/games/{game_id}/plays`,公开端点(可选 bearer):
@@ -118,11 +121,18 @@ procedure 在 `spacetime-module`,facade + mapper 在 `spacetime-client`,缓
## 落地与验收
- 实施边界:`spacetime-module` 新增批量自增 procedure 与 `SpacetimeType`;`spacetime-client` facade +
mapper;`api-server` 新增计数模块(增量 / 去重 / 限流 / flush worker / 关停 flush)、AppState 接线与公开
mapper;`api-server` 新增计数模块(增量 / 去重 / 限流 / flush worker)、AppState 接线与公开
端点;前端 `gameDistributionClient` 增 `recordGamePlay` 并在 `startGame()` 触发。
- 权威文档同步:`docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`(路由表与游戏分发合同节)、
`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md`(`game_distribution_game` 的 procedure 与
写入口径)。
- 验收判据:新游戏 `0` → 游客点一次 ≤10s 内显示 `1`;同身份 30 分钟内重复点击不增、不同身份各 `+1`;
超限流 `429` 且不写;下架 `404` 不计数但历史值保留;SIGTERM 关停前最后一窗已落库;计数接口任何失败都
超限流 `429` 且不写;下架 `404` 不计数但历史值保留;SIGTERM 关停允许丢最后一个未落库窗口;计数接口任何失败都
不影响游玩页;相关 Rust / 前端定向测试与 schema / DDD / 绑定 / DTO parity / 编码 / doc-index 门禁全绿。
## 修订记录
- 2026-10-03:初版。
- 2026-10-04:关停不再强制 flush(原「正常 SIGTERM/滚动重启必须在 `finalize_shutdown` 内 force flush」
作废)。理由:关停时最后一个窗口丢失概率极低,而强制 flush 需要把 worker 生命周期接进关停顺序并为在途
网络写入等待;按"perf 与简单优先"取舍,直接放弃该窗口。同日明确 flush 任一分片失败即丢弃剩余分片。