改用 HTTP 加载会话历史并更新 CentOS 7 发布包
This commit is contained in:
@@ -21,6 +21,7 @@ This directory contains guidelines for backend development. Fill in each file wi
|
||||
| [Logging Guidelines](./logging-guidelines.md) | Structured logging, log levels | To fill |
|
||||
| [Codex MCP 配置输出](./codex-mcp-config.md) | 旧类型配置兼容及 Codex 配置出口 | 已记录 |
|
||||
| [完整历史保存](./session-history.md) | 完整档案、快照缓存、并发及分页契约 | 已记录 |
|
||||
| [会话查询与实时订阅](./session-query.md) | HTTP 历史、运行快照、独立订阅与竞态隔离 | 已记录 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
100
.trellis/spec/backend/session-query.md
Normal file
100
.trellis/spec/backend/session-query.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# 会话查询与实时订阅契约
|
||||
|
||||
## 1. 适用范围与触发条件
|
||||
|
||||
浏览器打开会话、查看更早消息、索引用户目录、定位消息和恢复运行视图时适用。
|
||||
已有实现把这些读取绑定到 WebSocket 的 OPEN、鉴权和运行绑定;假 OPEN 时请求可能
|
||||
丢在旧连接里,直到45秒超时。历史查询必须有独立 HTTP 通道,重连只恢复实时订阅。
|
||||
这项代码事实不能用于断言每次现场故障都来自同一原因。
|
||||
|
||||
## 2. 接口与函数签名
|
||||
|
||||
```text
|
||||
GET /api/sessions/:id?requestId=<id>
|
||||
GET /api/sessions/:id/history?before=<非负整数>&requestId=<id>
|
||||
Authorization: Bearer <已有登录令牌>
|
||||
|
||||
handleSessionQueryApi(req, res, url, encodedId, historyPage = false)
|
||||
resolveSessionHistory(session, { count, before, persistedOnly: true })
|
||||
loadSession(id, { metadata: true, throwOnError: true })
|
||||
|
||||
WS → { type: 'subscribe_session', sessionId, requestId, historyRevision }
|
||||
WS ← { type: 'session_subscribed', sessionId, requestId, historyRevision, historyChanged, isRunning }
|
||||
```
|
||||
|
||||
## 3. 请求、响应与并发约束
|
||||
|
||||
- 首屏返回 `type='session_info'`、最近12条、`historyPending=false` 和会话元数据。
|
||||
分页返回 `type='session_history_chunk'`,向前最多24条,`remaining=0`。
|
||||
- 两者都提供 `sessionId/requestId/messages/historyTotal/historyBaseIndex/historyCursor/`
|
||||
`historyAvailable/historySource/historyRevision`;`requestId` 最多160字符,浏览器生成
|
||||
有界且唯一的代次标识,成功响应必须同时匹配会话和请求。
|
||||
- 首屏的 `runtime` 是完整 `resume_generating` 快照或 `null`,即使没有 WebSocket
|
||||
也能显示已产生输出。停止运行但尚未归档的保留态显示后须收束生成状态。
|
||||
- HTTP 只读取 cc-web 自身已保存记录;首屏不扫描原生日志、不协调跨会话、不清未读。
|
||||
归档按块有界读取;旧快照保留来源待核实状态。磁盘和 JSON 处理仍在同一服务进程,
|
||||
传输拆分不代表所有同步 IO 已异步化。
|
||||
- 订阅校验元数据、绑定实时输出、清未读并冲刷已有跨会话回复,不发送历史消息。
|
||||
比较清未读前的归档修订;有差异时由浏览器再通过 HTTP 对账。确认后返回清未读
|
||||
产生的新修订,避免元数据保存导致重复对账。
|
||||
- 首屏、正文分页、目录分页和消息定位均不检查 WebSocket 是否已连接或鉴权。
|
||||
WebSocket 关闭不能取消 HTTP 读取、清除分页状态或结束首屏加载。
|
||||
- 新选择、同会话新代次和退出视图取消旧 HTTP;控制器、视图代次和活动分页对象
|
||||
三重隔离迟到结果。错误恢复保留已有视图和分页游标,取消后清除加载标志。
|
||||
- `session_subscribed` 和带请求标识的运行快照必须属于当前订阅或视图。
|
||||
订阅触发的历史对账保留实时输出,不再应用较早的 HTTP runtime,也不重复订阅。
|
||||
- 若查询期间已收到该会话的 `done`,弃用较早快照并重新查询终态;不能让完成后的
|
||||
页面被旧 `isRunning=true` 快照覆盖。
|
||||
- HTTP 45秒硬超时只限制真实请求;每个成功、失败或取消出口都清理计时器。
|
||||
`Server-Timing` 和 `session_http_query` 记录请求、阶段、状态、数量和耗时,不记录正文。
|
||||
|
||||
## 4. 校验与错误矩阵
|
||||
|
||||
| 条件 | HTTP / 订阅行为 |
|
||||
|---|---|
|
||||
| 缺失或无效 Bearer | 401 `not_authenticated` |
|
||||
| URI 解码失败或 ID 含字母数字、连字符之外字符 | 400 `history_invalid_id`;不得清洗后别名到另一会话 |
|
||||
| 游标为负数、小数或非安全整数 | 400 `history_invalid_cursor` |
|
||||
| 会话确实缺失 | 404 `session_not_found` |
|
||||
| 元数据、清单或历史块读取失败 | 500 `history_read_failed`,禁止吞成404 |
|
||||
| 实时绑定失败 | WS `session_subscribe_failed`,历史继续可读 |
|
||||
| 新选择取消、迟到响应或不匹配订阅 | 不修改新视图及其加载状态 |
|
||||
|
||||
所有 HTTP 错误携带 `type='error'`、`code/message/sessionId/requestId`。未完成身份
|
||||
校验或 URI 解码时 `sessionId` 可以为空,不泄露磁盘路径及消息内容。
|
||||
|
||||
## 5. 正常、基本与失败场景
|
||||
|
||||
- 正常:57条归档关闭 WS 后首屏12条、继续分页24条和21条,按原顺序且无重复。
|
||||
- 基本:运行中会话在假 OPEN 时仍显示历史和完整运行输出,实时订阅独立恢复。
|
||||
- 交错:HTTP 读完后任务完成,订阅修订变化触发 HTTP 对账,最终回复显示且无生成占位。
|
||||
- 失败:A 响应晚于 B,A 的正文和运行态都不能覆盖 B;坏历史返回500并保留当前视图。
|
||||
|
||||
## 6. 必需回归与断言
|
||||
|
||||
- `scripts/session-http-load-frontend-unit.js` 执行生产请求函数:无 WS 读取、真实 abort、
|
||||
忽略取消后依然到达的响应、同会话代次、分页取消、完成交错、500和超时计时器释放。
|
||||
- `node scripts/regression.js --target session-http-load`:隔离真实服务,断 WS 后查询、
|
||||
首屏/分页、鉴权、坏 ID/游标、损坏清单/块、独立订阅、修订变化和完整运行快照。
|
||||
- `node scripts/session-http-load-regression.js --browser`:真实 Firefox 经转发层测试
|
||||
假 OPEN、读取途中断 WS、完全断连后切换、分页、迟到 A 响应、完成间隙及历史500。
|
||||
断言浏览器不发送 `load_session/load_history_page/resume_session` 查询历史。
|
||||
- 外部 CDN 不稳定时可设置 `CC_WEB_BROWSER_CDN_DIR`,使用与页面相同版本的原始
|
||||
`marked.min.js/highlight.min.js/mermaid.min.js/atom-one-dark.min.css` 本地夹具;仅转发层
|
||||
改写这些静态 URL,生产请求函数与渲染器保持原样,避免把登录前静态资源超时当作切换失败。
|
||||
- 所有数据、原生目录和 Codex home 锁路径必须隔离;不修改 HOME/CODEX_HOME 或生产锁。
|
||||
单次测试最多60秒,不能用生产会话的读写代替隔离验证。
|
||||
|
||||
## 7. 错误与正确示例
|
||||
|
||||
```js
|
||||
// 错误:已有令牌也必须先等长连接;假 OPEN 时只能等待业务超时。
|
||||
if (ws.readyState === 1 && wsAuthenticated) ws.send(JSON.stringify({ type: 'load_session', sessionId }));
|
||||
|
||||
// 正确:历史独立读取,成功应用后再接入实时订阅。
|
||||
const snapshot = await fetchSessionQuery(sessionId, requestId, { signal });
|
||||
handleServerMessage(snapshot);
|
||||
requestSessionResume(sessionId);
|
||||
```
|
||||
|
||||
生产函数还必须执行控制器身份、请求代次和完成事件版本校验,不能仅复制此示意代码。
|
||||
@@ -1,5 +1,9 @@
|
||||
# State Management
|
||||
|
||||
会话视图的 HTTP 读取、实时订阅、请求代次和完成事件交错规则,见
|
||||
[会话查询与实时订阅契约](../backend/session-query.md)。历史读取不能依赖 WebSocket
|
||||
连接、鉴权或重连;长连接断开不能取消正在进行的 HTTP 请求。
|
||||
|
||||
> How state is managed in this project.
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user