Files
Genarrative/docs/technical/API_SERVER_SPACETIME_CLIENT_POOLING_DESIGN_2026-04-23.md

4.6 KiB
Raw Blame History

api-server SpacetimeClient 连接池化设计 2026-04-23

更新时间:2026-04-23

1. 背景

当前 api-server 虽然在 AppState 中只持有一个 SpacetimeClient 实例,但 spacetime-client 内部仍然是:

  1. 每次 procedure / reducer 调用都执行一次 DbConnection::builder().build()
  2. 建连后立即 run_threaded()
  3. 拿到结果后立刻 disconnect()

也就是说,当前问题不是 api-server 每次请求都 new 一个 client而是

每次 client 调用都新建并销毁一条 SpacetimeDB 连接。

2. 本轮目标

本轮不继续维持“每次 HTTP 请求一条短连接”的阶段性策略。

本轮目标改为:

  1. api-server 进程内预热并持有一组可复用的 SpacetimeDB 连接
  2. 每次 HTTP 请求只从池里借一个可用连接执行 procedure / reducer
  3. 请求完成后归还连接,不主动断开
  4. 连接失效时自动剔除并按需重建

3. 为什么不直接引第三方池库

当前仓库使用的是 spacetimedb-sdk 生成的 DbConnection,不是传统 SQL client。

它的连接模型包含:

  1. on_connect
  2. on_disconnect
  3. run_threaded
  4. reducer / procedure callback

这类对象不是标准的 bb8 / deadpool 资源接口。

当前仓库也没有已经接入的通用资源池库,因此本轮优先在 spacetime-client 内实现最小可控池化层,而不是强行套第三方 SQL 风格池库。

4. 池化设计

4.1 结构

SpacetimeClient 内新增一个共享池状态:

  1. pool_size
  2. Semaphore
  3. Vec<Mutex<Option<PooledConnection>>>

其中 PooledConnection 持有:

  1. DbConnection
  2. run_threaded 返回的后台线程句柄
  3. 连接唯一 id

4.2 借还模型

每次调用 procedure / reducer 时:

  1. 先获取 Semaphore permit
  2. 选取一个空闲槽位
  3. 若槽位已有健康连接,则直接复用
  4. 若槽位为空或连接已坏,则现场重建
  5. 调用完成后归还槽位,但不主动断开连接

4.3 健康判断

当前阶段不做复杂心跳表。

最小健康策略如下:

  1. procedure / reducer callback 正常完成:连接保持在池中
  2. 连接在调用期间触发 on_disconnect:标记该槽位失效
  3. 下次借用该槽位时重建连接

4.4 并发策略

不共享同一个 DbConnection 给多个并发请求同时发 procedure。

原因:

  1. SDK callback 是异步回调模型
  2. 当前仓库调用层没有 request id 级别的统一 dispatcher
  3. 多请求共用一条连接容易把回调和调用方绑定关系搞乱

所以本轮采取:

一个池槽位同一时刻只服务一个请求。

这本质上是“连接池”,不是“多路复用单连接”。

5. 默认规模

默认池大小取小值,避免本地开发和轻量部署浪费连接:

  1. 默认 4
  2. 允许通过环境变量覆盖,例如 GENARRATIVE_SPACETIME_POOL_SIZE

6. 错误与超时策略

沿用现有 SpacetimeClientError 口径:

  1. 建连失败:Build / Runtime
  2. 连接在返回前断开:ConnectDroppedProcedure
  3. 调用超时:Timeout

新增规则:

  1. 借用池槽位超时,也映射为 Timeout
  2. 某槽位一旦确认断线,必须在池中清空,不能继续复用脏连接
  3. procedure / reducer 等待结果无论成功、失败还是超时,都必须先归还租约再向上层返回,避免槽位泄漏把池卡死
  4. 调用期间若连接先收到 on_disconnect,当前阶段只标记坏连接;若业务回调未及时返回,则最终由调用超时路径统一清槽并回传错误

7. 与现有文档的关系

之前 AXUM_TO_SPACETIMEDB_ASSET_OBJECT_CONFIRM_CALL_DESIGN_2026-04-21.md 中写明“当前阶段每次 HTTP 请求可以建立一条短连接,待真实链路验证稳定后再评估连接池或长连接复用”。

本轮就是进入这个“下一阶段”:

  1. 保留 on_connect 后再发请求的约束
  2. 去掉“请求完成立即断开”的短连接策略
  3. 改成 spacetime-client 进程内连接池

8. 验收标准

落地后至少满足:

  1. api-server 启动后,SpacetimeClient 不再为每次调用单独建连
  2. 同一进程内连续多个 API 请求可以复用池中连接
  3. 单个连接断开后不会污染后续请求
  4. api-server 调用侧无需修改业务 handler

9. 一句话结论

本轮不引第三方 SQL 风格池库,而是在 spacetime-client 内实现一层:

面向 DbConnection 的最小连接池,让 api-server 复用长活连接,而不是每次调用都单独建连。