Handle SpacetimeDB migration imports with chunked uploads
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-30 15:20:49 +08:00
parent 1ccb8a710d
commit 22f3f963de
9 changed files with 567 additions and 20 deletions

View File

@@ -8,7 +8,7 @@ SpacetimeDB reducer 必须保持确定性,不能访问文件系统和网络。
1. `spacetime-module` 内的导出 procedure 读取迁移白名单表,并直接返回迁移 JSON 字符串。
2. Node 运维脚本默认通过 `spacetime call` 调用导出 procedure把返回的 JSON 字符串写入本地文件。
3. Node 运维脚本读取本地 JSON 文件内容。导入时默认先通过 `POST /v1/identity` 创建临时 Web API identity/token再用当前 CLI 登录态把该 identity 授权为迁移操作员,最后通过 HTTP request body 把 JSON 字符串传给导入 procedure。
3. Node 运维脚本读取本地 JSON 文件内容。导入时默认先通过 `POST /v1/identity` 创建临时 Web API identity/token再用当前 CLI 登录态把该 identity 授权为迁移操作员;小文件直接通过 HTTP request body 传给导入 procedure,大文件自动切成分片上传后再提交
4. 导入 procedure 校验 JSON 与表白名单后,在事务中写入目标数据库。
procedure 不再访问 HTTP 文件桥,也不接收部署机本地文件路径。这样可以避开 SpacetimeDB 对 private/special-purpose 地址的 HTTP 访问限制,并避免把 private 表内容通过临时 HTTP 服务转发。
@@ -30,6 +30,8 @@ SpacetimeDB Wasm 运行环境不支持 `std::time::SystemTime::now()`procedur
`database_migration_operator` 只控制迁移 procedure 调用权限,不会被导出或导入,避免把源库的运维权限复制到目标库。
大文件分片导入额外使用私有临时表 `database_migration_import_chunk` 暂存上传片段。这张表只保存当前导入过程的中间数据,提交成功后自动删除,失败时由脚本尽量调用清理 procedure它不在迁移白名单内也不会被导出到业务迁移 JSON。
首次授权时,操作员表为空,必须通过编译进模块的 `GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET` 引导密钥授权第一位操作员。发布脚本会在构建或发布 SpacetimeDB 模块时自动生成一份强随机引导密钥、注入 wasm 编译环境,并在控制台显示;运维人员必须记录对应数据库本次发布输出的密钥。表内已经存在操作员后,后续授权与撤销只能由已有操作员发起;此时不再接受引导密钥越权扩权。
新增 procedure
@@ -99,6 +101,14 @@ node scripts/spacetime-revoke-migration-operator.mjs \
`import_database_migration_incremental_from_file(ctx, input)`
`put_database_migration_import_chunk(ctx, input)`
`import_database_migration_from_chunks(ctx, input)`
`import_database_migration_incremental_from_chunks(ctx, input)`
`clear_database_migration_import_chunks(ctx, input)`
输入字段:
- `migration_json`: 导出 procedure 生成的完整迁移 JSON 字符串。
@@ -106,6 +116,15 @@ node scripts/spacetime-revoke-migration-operator.mjs \
- `replace_existing`: 是否先清空本次迁移文件内实际导入的目标表。不会清空迁移文件未包含的表;分批迁移时只覆盖当前批次。
- `dry_run`: 只解析和统计,不写表。
分片导入字段:
- `upload_id`: 本次分片上传的唯一 ID只允许 ASCII 字母、数字、短横线或下划线。
- `chunk_index`: 当前分片序号,从 `0` 开始。
- `chunk_count`: 本次上传总分片数。
- `chunk`: 当前迁移 JSON 片段,单片最多 `1048576` bytes。
Node 导入脚本默认在文件超过 `524288` bytes 时使用分片导入;如果小文件直接导入仍遇到 `SpacetimeDB HTTP 413: Failed to buffer the request body: length limit exceeded`,也会自动退回分片流程。可通过 `--chunk-size <bytes>` 或环境变量 `GENARRATIVE_SPACETIME_MIGRATION_CHUNK_SIZE` 调小单片大小。
导入模式:
- 默认严格追加:不清空目标表,逐行插入;遇到主键或唯一约束冲突时失败并回滚,适合确认目标库没有同表旧数据时使用。
@@ -252,8 +271,9 @@ node scripts/spacetime-import-migration-json.mjs \
1. `POST /v1/identity` 创建临时 Web API identity/token。
2. 使用当前机器 `spacetime` CLI 登录态调用 `authorize_database_migration_operator`,授权这个临时 identity。
3. 使用 `Authorization: Bearer <临时 token>` 调用 `import_database_migration_from_file`,把完整迁移 JSON 放在 HTTP body 中
4. 导入请求结束后,脚本会用同一个临时 Web API token 调用 `revoke_database_migration_operator`,撤销该临时 identity
3. 使用 `Authorization: Bearer <临时 token>` 导入迁移 JSON。文件不超过 `--chunk-size` 时直接调用 `import_database_migration_from_file`;超过阈值或直接导入触发 HTTP 413 时,先逐片调用 `put_database_migration_import_chunk`,再调用 `import_database_migration_from_chunks``import_database_migration_incremental_from_chunks`
4. 分片上传或提交失败时,脚本会尽量调用 `clear_database_migration_import_chunks` 清理临时分片
5. 导入请求结束后,脚本会用同一个临时 Web API token 调用 `revoke_database_migration_operator`,撤销该临时 identity。
所有直接访问 SpacetimeDB Web API 的 POST 请求必须显式发送 `Content-Type: application/json`。部分 SpacetimeDB 版本不会接受省略 content type 或附带非预期 media type 的请求,即使 body 本身是合法 JSON也会返回 `HTTP 415`
@@ -265,6 +285,8 @@ node scripts/spacetime-import-migration-json.mjs \
`--dry-run` 不会模拟目标库主键或唯一约束冲突,因此增量模式的 `skipped_row_count` 只有真实导入时才准确。
如果 Jenkins 或 SpacetimeDB 返回 `HTTP 413`,优先降低导入流水线的 `CHUNK_SIZE`,例如 `262144`。该参数只影响上传到 procedure 的单片 request body不改变迁移 JSON 的表范围和导入语义。
不要在只想追加数据时使用 `--replace-existing`。该参数会先删除覆盖范围内的目标表旧数据,再插入迁移文件中的数据;如果源文件不是完整快照,会造成目标表数据丢失。
如需分批迁移,可用逗号分隔表名:
@@ -303,6 +325,6 @@ node scripts/spacetime-export-migration-json.mjs \
## 风险与限制
迁移 JSON 作为 procedure 返回值和 HTTP request body 传递,会受 SpacetimeDB 调用响应体、请求体以及中间代理大小限制。数据量较大时,先按 `include_tables` 分批迁移;若单表本身过大,再补充分片 procedure而不是恢复 HTTP 文件桥
迁移 JSON 作为 procedure 返回值和 HTTP request body 传递,会受 SpacetimeDB 调用响应体、请求体以及中间代理大小限制。导入端已经内置分片上传来规避 `HTTP 413` 请求体限制;如果导出响应本身过大,仍需先按 `include_tables` 分批导出
`spacetime call` 在 PowerShell 中手写 JSON 容易被剥掉双引号。导入大文件时也不能把完整 JSON 放进命令行参数,否则 Linux 会在启动子进程时返回 `spawn E2BIG`。推荐使用仓库里的 Node 脚本,由脚本直接走 Web API request body避免 shell 二次处理和命令行长度限制。