Merge branch 'master' into codex/issue-187
This commit is contained in:
@@ -16,6 +16,30 @@
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-27 退款 emergency spool 容量溢出保持可恢复
|
||||
|
||||
- 背景:本机 emergency spool 仅作为 SpacetimeDB 完全不可达时的最后恢复路径,原有 `MAX_BYTES` 分支会直接返回 `Dropped`,导致扣费已经完成但没有可重放记录。
|
||||
- 决策:达到普通 outbox `MAX_BYTES` 时,将退款记录写入同一持久目录的 `refund-overflow-*` 文件;该文件与普通 pending 文件一样由启动恢复和后台 worker 重放到 SpacetimeDB,且按 refund ledger id 保持幂等。溢出文件不计入普通阈值,但必须触发容量告警;底层磁盘写入失败仍进入关键退款人工补偿流程。
|
||||
- 影响范围:api-server wallet refund emergency spool、资产失败退款日志、loadtest / 预览 Compose 持久卷、后端架构与开发运维文档。
|
||||
- 验证方式:运行 api-server `wallet_refund_outbox` 定向测试,确认超限写入并保留 overflow 文件;运行 SpacetimeDB profile 测试、Compose 配置校验、编码和 diff 门禁。
|
||||
|
||||
## 2026-08-27 短期认证状态进入共享 typed projection
|
||||
|
||||
- 背景:短信验证码和微信 OAuth state 仍只存在 API 进程内 HashMap,多节点请求或 API 重启会直接丢失,无法满足无粘性会话的鉴权恢复要求。
|
||||
- 决策:`AuthStoreProjectionView` 增加 `phone_codes` 与 `wechat_states` typed 字段,由 `auth_store_projection_meta` 以 JSON 投影持久化;启动恢复、CAS 同步和失败后的权威刷新都覆盖这两类短期状态。验证码哈希使用部署级稳定盐(当前复用 `GENARRATIVE_JWT_SECRET`),各 API 节点必须一致;发码前先刷新权威投影并用占位验证码记录做一次 projection CAS,只有占用成功才调用短信 provider,避免跨节点冷却竞态;认证 handler 在发码、消费验证码、创建/消费微信 state 后都要完成 projection sync,失败即返回服务错误;所有会读取或变更本机认证工作集的认证主链路(登录、刷新、`/me`、会话管理、密码、绑定和微信 state)在领域操作前先从正式投影做一次受 CAS 保护的只读刷新,受保护 Bearer 中间件也会在进入业务 handler 前执行同样的刷新,刷新失败时 fail closed,不能依赖粘性会话;同步遇到 CAS 冲突时,若本次尝试期间没有新的本地变更则恢复正式快照,若仍有待同步 revision 则由后续认证请求重试,避免节点永久卡在 pending。微信 OAuth state 设置有界活动数量,避免单个 JSON 投影无界膨胀。短期状态仍由 `module-auth` 内存工作集执行领域校验,但不再把本机 HashMap 当作持久化或跨节点真相。
|
||||
- 影响范围:`module-auth` projection、`spacetime-module` auth schema/procedure、`spacetime-client` bindings/facade、api-server 手机号 / 微信 handler、认证架构与运维文档。
|
||||
- 验证方式:运行 module-auth projection roundtrip(验证码可跨恢复校验、微信 state 可跨恢复消费)、SpacetimeDB schema/runtime/DDD 门禁、api-server 定向测试、编码和 diff 检查。
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-27 外部生成历史采用受控保留清理
|
||||
|
||||
- 背景:`external_generation_job`、`external_generation_job_summary` 与 `external_generation_job_event` 都是持久化表;摘要和 payload 边界收紧后,已确认的终态历史仍会继续占用 SpacetimeDB 常驻内存,且事件审计链会随任务数量增长。
|
||||
- 决策:新增仅 migration operator 可调用的 `prune_external_generation_job_history_and_return`。默认按 `source_module=editor-canvas`、30 天保留期和 `job_id` 游标分批运行;只删除主任务与摘要状态一致、属于 completed / failed / cancelled、摘要已有 `notification_acknowledged_at` 且终态时间达到 cutoff 的任务,并在同一事务内删除该任务的全部事件、摘要和主任务。默认 dry-run,必须固定 dry-run 返回的 cutoff 后再 apply;pending / running、未确认通知、摘要缺失或状态不一致的数据永不删除。其他 source module 必须显式指定并单独评估;资产对象和钱包流水不随任务历史删除;不新增自动定时器或 runtime 清理权限。
|
||||
- 影响范围:`server-rs/crates/spacetime-module/src/external_generation.rs`、外部生成事件 job_id 单列索引、SpacetimeDB 生成 bindings、`scripts/spacetime-maintain-external-generation-jobs.mjs`、架构与生产运维文档。
|
||||
- 验证方式:覆盖终态 / 活跃态 / 已确认与未确认摘要、状态或身份不一致、cutoff 边界测试;运行 SpacetimeDB module tests/check、bindings 生成、schema/encoding/diff 门禁,并在维护窗口先 dry-run 再 apply。
|
||||
- 关联文档:`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`、PR #203。
|
||||
|
||||
## 2026-08-27 SpacetimeDB 工具链统一升级到 2.8.3
|
||||
|
||||
- 背景:SpacetimeDB 2.8.0 引入 TypeScript submodule 与调度延迟观测,2.8.1 修复 v1 WebSocket 订阅移除死锁、TypeScript SDK `array<u8>` 读缓存别名和 Rust string 默认值支持,2.8.2 修复 table accessor 改名自动迁移,2.8.3 修复 scheduled function 从实际执行时间重排导致的长期漂移。仓库若继续锁定 2.7.0,会保留这些已知运行时与 SDK 问题。
|
||||
@@ -1317,8 +1341,8 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- OSS 固定恢复入口为 `<prefix>/<database>/latest.json`。CAS 文件和 full/history catalog 保持不可变;latest pointer 只保存最新 full catalog 与已发布 history catalog 的 object key、长度和 SHA,不包含主机绝对路径或文件内容。每次 state 变化先验真全部引用 catalog,再覆盖上传并 HEAD 验真 latest pointer,成功后才落本地 state;history 还必须在 pointer 成功后才允许删除源文件。全新机器可仅凭 bucket、database、prefix 与 OSS 凭据自动下载 pointer 和 full catalog。
|
||||
- dev 带宽不足时,允许把已冻结的 dev 基线经 `10.2.0.10 -> 10.2.4.16` 内网 rsync 到 release 独立 staging,再用 release 出口上传 dev bucket;staging 不得指向 release `/stdb`,不得停止或修改 release 服务,传输凭据必须临时创建并在演练后移除。catalog 不记录 staging 绝对路径,files state 可回传 dev 继续 history。
|
||||
- 恢复边界:恢复时默认从 OSS `latest.json` 自动定位 full catalog,创建目录并按相对路径下载每个对象、逐文件校验长度与 SHA;本地 state 只用于备份续跑,不再是异机恢复前置条件。远程 dev 已完成真实 OSS、清理、重启和异机隔离恢复演练;release timer 与 publish 前备份继续保持原行为。
|
||||
- systemd 接线:主 service 保持 `archive-full`。Server-Provision 新增默认值为 `archive-full` 的 `DATABASE_BACKUP_PROFILE`;dev 或 release 显式选择 `files-history` 时,必须为各自主机指定独立 work-dir,并先用 current release 脚本执行 history dry-run,确认已有 full state 后才安装仓库托管 drop-in,并删除现场手写旧 drop-in。切回默认 profile 必须删除所有 history 覆盖。
|
||||
- 影响范围:`scripts/database-backup-to-oss.mjs`、备份门禁、生产 env 示例、systemd 模板、Server-Provision、SpacetimeDB 运维与恢复流程;release timer 可在独立 baseline 验证后显式选择 profile,publish 前备份是否切换仍需单独决策。
|
||||
- systemd 接线:主 service 保持 `archive-full`。Server-Provision 新增默认值为 `archive-full` 的 `DATABASE_BACKUP_PROFILE`;development 可显式选择 `files-history`,必须指定独立 work-dir 并先用 current release 脚本执行 history dry-run,确认已有 full state 后才安装仓库托管 drop-in;release 拒绝 `files-history`,直到流式 catalog 改造完成,以免大目录扫描再次触发 Node 内存峰值。切回默认 profile 必须删除所有 history 覆盖;备份 unit 同时设置 Node heap 与 systemd memory 上限,避免备份异常拖垮业务主机。
|
||||
- 影响范围:`scripts/database-backup-to-oss.mjs`、备份门禁、生产 env 示例、systemd 模板、Server-Provision、SpacetimeDB 运维与恢复流程;release timer 固定使用 archive-full,publish 前备份是否切换仍需单独决策。
|
||||
- 验证方式:`npm run check:database-backup`、`npm run check:production-ops`、`npm run check:encoding`、`git diff --check`;dev 现场必须完成逐文件 full catalog、重复 full 零 PUT、history dry-run、上传后清理、STDB 重启和按 catalog 隔离恢复 roundtrip。
|
||||
- 关联:<https://github.com/clockworklabs/SpacetimeDB/issues/5542#issuecomment-4981566448>。
|
||||
|
||||
@@ -7763,3 +7787,17 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 决策:`.codex/skills/` 下的 SpacetimeDB 指导收敛为单一 `.codex/skills/genarrative-spacetimedb/SKILL.md`。官方 `spacetimedb` 插件负责通用 concepts、Rust server、CLI、TypeScript client 和 MCP 知识;项目 skill 只保留 Genarrative 的架构边界、schema/migration 门禁、目标 server 安全规则、运行时排障和验证路径。
|
||||
- 路由:涉及 SpacetimeDB 的任务统一先读取项目适配 skill,再按需读取 `spacetimedb:concepts`、`spacetimedb:rust-server`、`spacetimedb:cli`、`spacetimedb:typescript-client` 或 `spacetimedb:mcp`。插件通用示例不得覆盖项目禁止 `maincloud`、禁止人工 `spacetime --root-dir`、显式 server 和后端分层等约束。
|
||||
- 安装:团队环境缺少插件时使用 `codex plugin marketplace add clockworklabs/SpacetimeDB --sparse .agents --sparse codex-plugin` 和 `codex plugin add spacetimedb\@spacetimedb-plugins`;个人配置、缓存和凭据不进入仓库。
|
||||
|
||||
## 2026-08-27 退款 outbox 主路径迁入 SpacetimeDB
|
||||
|
||||
- 决策:`profile_wallet_refund_outbox` 是跨 API 节点退款的正式持久化队列。扣费失败、外部生成 attempt 失败或最终 lease 过期时,在同一个 SpacetimeDB 事务内按 `refund_ledger_id` 幂等写入 pending 行;worker 从库内 pending 行批量处理,退款账本写入与 outbox 成功删除保持在同一事务内,失败由 `available_at` / `attempts` 驱动重试。`asset_operation_wallet_settlement` 继续负责退款先于 consume 可见时的取消 intent,阻止迟到扣费。只有 SpacetimeDB 完全不可达时,api-server 才写本机 `wallet-refund-outbox` emergency spool;本机文件不能替代库内队列,必须持久挂载、告警、恢复演练并支持人工补偿。
|
||||
- 影响范围:`profile_wallet_refund_outbox` 表及 bindings、runtime enqueue/process procedure、外部生成失败事务、inline 资产退款、api-server 跨节点 worker 和 emergency spool、后端架构与开发运维文档。
|
||||
- 验证方式:运行 `npm run spacetime:generate`、`npm run check:spacetime-schema`、`npm run check:server-rs-ddd`、`cargo check -p spacetime-module -p spacetime-client -p api-server --manifest-path server-rs/Cargo.toml`、退款 outbox / asset billing / external generation 定向测试、`npm run check:encoding` 和 `git diff --check`。
|
||||
|
||||
## 2026-08-27 release 内存增长修复与备份 OOM 恢复兜底
|
||||
|
||||
- 决策:外部生成 worker 每轮主动 `try_join_next` 回收已完成 `JoinHandle`,避免持续有队列任务时只归还 semaphore permit 却让 `JoinSet` 句柄集合无界增长;超时脱管任务在 abort 后等待句柄结束,执行许可保持到 work 真正结束或被取消。
|
||||
- 决策:`module-ai` 的阶段终态写入与流式增量统一受文本、结构化 JSON、warning 和全局 retained 工作集上限约束;认证投影恢复对过滤后的 refresh session 重新计数,超过 8192 条直接拒绝启动恢复,避免超限快照灌入内存。
|
||||
- 复审补充:`spacetime-module` 的 AI procedure 复用同一组任务元数据 / payload / 输出 / 结果引用上限,流式文本聚合超限时回滚事务,terminal task 收口后删除 `ai_text_chunk` 明细,避免真实持久化链路绕过内存边界。
|
||||
- 决策:备份脚本停库前写入受保护 `.spacetimedb-stopped` marker,正常恢复完成后清理;systemd 备份 service 通过 `MemoryHigh/MemoryMax/OOMPolicy` 和 `ExecStopPost` 在 Node OOM kill、无法执行 JS finally 时兜底拉起 SpacetimeDB、API、worker、controller,恢复不完整则保留 marker。
|
||||
- 验证:worker/module-auth/module-ai 定向 Rust 测试、database-backup/production-ops/encoding 门禁和 `git diff --check` 必须在提交前通过;release 现场需按 archive-full 重新 provision 并核验旧 files-history drop-in 已删除、四个服务 active。
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user