SpacetimeDB 模块发布完整指南:从spacetime build到spacetime publish的构建、发布与迁移实战
【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB
本篇指南系统讲解 SpacetimeDB 中模块从源码到线上数据库的全流程:如何针对不同运行时(Rust/C# 编译为 WASM、TypeScript 打包为 V8 JavaScript)构建模块,如何通过spacetime publish创建新数据库或原子化更新已有数据库,以及--break-clients、--delete-data、--yes等关键选项的适用场景。读完本文,你将掌握模块发布命令的完整参数体系、底层执行链路(crates/cli/src/subcommands/publish.rs)、自动迁移的兼容性边界,以及一套可落地的发布与回滚策略。
发布前必读:理解模块的运行目标
在发布之前,需要先明确模块的编译产物形态,因为不同的服务端语言对应不同的运行时:
- Rust 与 C# 模块:编译为 WebAssembly(WASM),由 SpacetimeDB 内置的 WASM 运行时执行;
- TypeScript 模块:通过打包器产出可在 V8 JavaScript 引擎中运行的 bundle,不经过 WASM。
这一区分在源码层面有直接体现:spacetime publish在决定发布产物时会检查wasm_file与js_file两条路径,并携带host_type(Wasm或Js)查询参数上传给服务端(见 crates/cli/src/subcommands/publish.rs 与 L635 的builder.query(&[("host_type", host_type)]))。因此,发布命令本身并不关心语言的差异,它只关心最终交付的是哪种运行时产物。
模块目录约定
发布时 CLI 会在当前目录下查找模块工程,默认查找顺序为:
- 当前目录下的
spacetimedb/子目录; - 当前目录本身。
该逻辑实现在default_publish_module_path(crates/cli/src/subcommands/publish.rs):若spacetimedb/目录存在则优先使用,否则回退到当前目录。这解释了为什么官方模板(如 templates/basic-rs/spacetimedb、templates/basic-ts/spacetimedb)统一把模块工程放在spacetimedb/下——发布、构建命令无需额外指定路径即可命中模块。
第一步:构建模块(spacetime build)
进入模块目录(通常是项目内的spacetimedb/),执行:
spacetime build该命令会编译你的模块并校验其结构。从源码看,spacetime build实际完成的工作包括:
- 解析模块路径(
--module-path,缺省时同样遵循spacetimedb/子目录优先的规则,见 crates/cli/src/subcommands/build.rs); - 根据模块语言分发到对应的构建任务(Rust / C# / TypeScript / C++,见 crates/cli/src/tasks 目录下的
rust.rs、csharp.rs、javascript.rs、cpp.rs); - 对
src/目录进行 lint,检查非功能性print语句(默认 lint 目录为src,可通过--lint-dir覆盖或置空关闭); - 产出可发布的 WASM 二进制或 JS bundle。
spacetime build常用选项
| 选项 | 说明 |
|---|---|
-p, --module-path <MODULE_PATH> | 模块工程路径,默认spacetimedb/子目录,其次当前目录 |
--lint-dir <DIR> | 检查非功能性print语句的目录,默认src,设为空字符串则跳过 lint |
-d, --debug | 以 debug 而非 release 模式构建,适合本地快速迭代,官方注释明确“不建议用于 CI” |
--features <FEATURES> | 透传给构建进程的附加特性(如 Rust 模块的--features feature1,feature2) |
--dotnet-version <VERSION> | 指定 C# 项目目标 .NET SDK 主版本(如 8 或 10),缺省时自动检测 |
:::tip 如果最终目的是发布,则无需单独执行spacetime build——spacetime publish会在需要时自动触发构建。对于全部构建选项,可参考 spacetime build CLI 参考。 :::
第二步:发布前认证(spacetime login)
在发布到托管服务之前,需要先通过认证建立身份:
spacetime login命令会打开浏览器窗口完成认证,认证完成后凭据保存在本地。从 crates/cli/src/subcommands/login.rs 的实现看,登录流程包含如下细节:
- 默认向
https://spacetimedb.com请求一次性 token,然后轮询认证服务器等待用户在浏览器中批准(web_login,L206-L250); - 认证成功后换取 SpacetimeDB 登录令牌(
spacetimedb_login,L264-L283),并将令牌保存到本地配置; - 支持
--no-browser(不自动打开浏览器,打印 URL 由用户手动打开)、--token <TOKEN>(直接使用已有令牌跳过整个流程)、spacetime login show(查看当前登录身份,加--token可同时显示令牌); - 自托管场景可用
--server-issued-login直接向目标服务器登录,但这种登录方式对其他服务器无效。
若未登录就执行发布,CLI 会尝试交互式登录(get_auth_header内部处理,见 crates/cli/src/subcommands/publish.rs);在非交互脚本中可通过--yes=skip-login显式跳过登录提示。
第三步:发布新数据库
发布模块并创建新数据库:
spacetime publish <DATABASE_NAME>数据库命名规则
<DATABASE_NAME>必须满足正则/^[a-z0-9]+(-[a-z0-9]+)*$/,即只能由小写 ASCII 字母和数字组成,多个单词之间用连字符-分隔(如my-chat-app)。位置参数也接受数据库 identity。该规则定义在 CLI 参考 的 Arguments 小节,并由源码中的validate_name_or_identity执行校验(crates/cli/src/subcommands/publish.rs)。
发布命令的完整执行链路
spacetime publish <DATABASE_NAME>依次完成:
- 构建模块(如果尚未构建):通过
build::exec_with_argstring触发,可透传--build-options、NativeAOT 与 .NET 版本设置(crates/cli/src/subcommands/publish.rs); - 创建新数据库:若提供了数据库名,则向
/v1/database/<name>发送 PUT 请求;若未提供名称,则 POST 到/v1/database(L589-L617); - 上传并安装模块:将程序字节码作为请求体发送(
builder.body(program_bytes).send(),L637); - 运行
init生命周期 reducer(若模块中定义了); - 开始接受客户端连接。
保存数据库 identity
发布成功后,CLI 会输出数据库的域名与 identity。务必保存这个 identity——后续的数据库管理(如spacetime logs、spacetime call、spacetime describe、spacetime delete)都要靠它或域名来定位数据库。若目标是官方托管服务(maincloud.spacetimedb.com),还会额外打印 Dashboard 地址(L655-L659)。
第四步:更新已有数据库与自动迁移
对已发布数据库重新执行同一条命令即可完成更新:
spacetime publish <DATABASE_NAME>服务端会依次进行:
- 构建你的模块;
- 尝试自动迁移 schema,使旧数据适配新模块定义;
- 原子化替换新模块——发布要么整体成功、要么整体失败,不会出现半新半旧状态;
- 维持既有客户端连接不中断。
自动迁移的兼容性边界
“schema”指模块代码中声明的表、reducer、procedure、视图及其依赖类型的集合。SpacetimeDB 的自动迁移(详见 自动迁移文档)把变更分为三类:
安全变更(总是允许,不破坏客户端):新增表、新增索引、增删Auto Inc注解、表从私有转公开、新增 reducer、移除Unique约束。
潜在破坏性变更(允许迁移,但未更新客户端可能报错):在表末尾新增带默认值的列、变更或移除 reducer(旧客户端调用会得到运行时错误)、表从公开转私有(已订阅的客户端报错)、仅改访问器名而保留规范名、移除空表(会断开活动客户端)、移除Primary Key注解、移除索引(可能使基于半连接的订阅查询失效)。
禁止变更(自动迁移会直接失败):移除非空表、移除或修改既有列(含类型/规范名/顺序变更)、新增无默认值的列、在表中间插入列、变更表是否用于scheduling、新增Unique或Primary Key约束、更改索引访问器名。
如果你的更新无法自动迁移,应参考 增量迁移文档 中的生产级模式;开发测试阶段可接受数据丢失时,才考虑使用--delete-data整体重置。
破坏性变更:--break-clients
如果更新包含无法自动迁移的破坏性变更,需要显式声明接受客户端被破坏:
spacetime publish --break-clients <DATABASE_NAME>⚠️警告:这会使尚未升级到新 schema 的既有客户端无法继续工作。
从源码看,--break-clients等价于--yes=break-clients:它跳过“此次变更会 BREAK 既有客户端”的确认提示,但不会在变更会导致数据库数据删除时强制发布(crates/cli/src/subcommands/publish.rs)。真正决定是否清空数据的是--delete-data(见下文)。其底层通过pre_publish接口向服务端上传模块字节码,服务端返回迁移计划;若计划标记break_clients为真,CLI 会提示确认,确认后携带policy=BreakClients令牌执行发布(apply_pre_publish_if_needed,L756-L824)。
如果本次发布是从 1.x 升级到 2.0 的大版本升级,请先阅读 1.x 到 2.0 升级说明。CLI 检测到大版本升级时会要求输入upgrade确认,并提示升级后无法回退到 1.0(见confirm_major_version_upgrade,L345-L368)。
清空数据:--delete-data
彻底重置数据库并删除全部数据:
spacetime publish <DATABASE_NAME> --delete-data⚠️警告:这会永久删除数据库中的所有数据!
--delete-data(短选项-c)支持三种取值,控制清空发生的时机:
| 取值 | 行为 |
|---|---|
always | 发布到既有数据库前,无条件销毁该模块关联的全部数据 |
on-conflict | 仅当发布会遇到无法自动迁移的破坏性 schema 变更时才清空数据 |
never | 从不主动清空(默认值);若必须手动迁移,发布将中止 |
执行always清空前,CLI 会打印This will DESTROY the current ... module, and ALL corresponding data.并二次确认(confirm_and_clear,L325-L343)。在自动化流水线中可用--yes=delete-data跳过该确认——但请务必确认清空是可接受的。
第五步:发布选项全景
spacetime publish的完整签名是:
spacetime publish [OPTIONS] [name|identity]除上文已讲的参数外,常用选项如下(均来自 CLI 参考):
| 选项 | 说明 |
|---|---|
-p, --module-path <MODULE_PATH> | 模块工程路径(绝对或相对),默认spacetimedb/子目录,其次当前目录 |
-b, --bin-path <WASM_FILE> | 直接发布已编译的 WASM 二进制,跳过构建;与--module-path、--build-options、--js-path互斥 |
-j, --js-path <JS_FILE> | UNSTABLE:直接发布已打包的 JavaScript 文件,跳过构建 |
--build-options <BUILD_OPTIONS> | 透传给构建命令的选项,例如--build-options='--lint-dir=' |
-s, --server <SERVER> | 托管数据库的服务器昵称、域名或 URL |
--parent <PARENT> | 父数据库的域名或 identity;新数据库继承父库的团队权限,只能在创建时设置,更新时无效 |
--organization <ORGANIZATION> | 新数据库归属的组织(名称或 identity),组织成员权限适用于该库;同样只能在创建时设置 |
--anonymous | 以匿名身份执行操作 |
-y, --yes [<YES>] | 跳过确认提示;见下文详述 |
--no-config | 忽略spacetime.json配置 |
--env <ENV> | 配置文件的层级环境名(如dev、staging) |
--native-aot | 对 C# 模块使用 NativeAOT-LLVM 编译(实验性;支持 Windows,以及安装了 .NET 10 的 Linux) |
--dotnet-version <VERSION> | 指定 C# 项目目标 .NET SDK 主版本,缺省自动检测 |
--yes:跳过各类确认提示
--yes(-y)用于自动化场景跳过交互确认。不带值时等价于--yes=all。可精细指定要跳过的提示类别,多个值可用逗号分隔或重复传参:
spacetime publish my-db --yes=migrate,break-clients spacetime publish my-db --yes=migrate --yes=break-clients--yes取值 | 跳过的提示 |
|---|---|
all | 等价于传入下面所有选项 |
remote | “发布到非本地服务器?”确认 |
migrate | 迁移确认(例如大版本升级) |
break-clients | “会 BREAK 既有客户端”确认 |
skip-login | 不提示登录,认证采用非交互方式 |
delete-data | “将 DESTROY ... 全部数据”的破坏性确认 |
注意:值必须用=附着,即--yes my-db会把my-db当作数据库名而非--yes的值(见 crates/cli/src/subcommands/publish.rs 的 clap 定义)。
使用spacetime.json管理发布目标
从 crates/cli/src/spacetime_config.rs 的配置模型看,spacetime publish会优先读取项目根目录的spacetime.json(可通过--no-config忽略、--env切换环境分层)。配置文件以数据库为核心组织目标(database、server、module_path、build_options、wasm_file、js_file、parent、organization等键,见build_publish_schema,crates/cli/src/subcommands/publish.rs),支持父子目标继承:
- CLI 传入的数据库名会以 glob 模式匹配配置文件中的多个目标,一次发布多个数据库;
spacetime init生成随机数据库后缀时,CLI 传入的名称与配置不一致也会正确合并模块级配置;- 若配置中存在多个目标而 CLI 未指定数据库名,会提示指定名称或 identity 以选中单一目标。
这使得把发布目标固化到仓库配置中、团队共享一致的发布参数成为可能。
发布流程的底层调用链
综合以上内容,一次发布在 CLI 侧的完整调用链为(对应 crates/cli/src/subcommands/publish.rs 的exec_with_options→execute_publish_configs):
- 加载
spacetime.json配置(或仅用 CLI 参数),解析出发布目标集合; - 确定
module_path与构建选项;若指定--bin-path/--js-path则跳过构建; - 获取认证头(未登录且未加
--yes=skip-login时触发登录); - 校验数据库名与 parent;
- 本地构建(或读取预编译产物),读取程序字节码;
- 对非本地服务器(非
localhost/127.0.0.1)执行发布前二次确认; - 若有数据库名,先调用
pre_publish接口获取迁移计划(新库返回 404 视为无需迁移),按计划提示迁移/破坏性变更确认,或触发清空流程; - PUT
/v1/database/<name>(或 POST/v1/database)上传模块,附加host_type、parent、org、num_replicas等参数; - 解析
PublishResult:打印“Created new / Updated database with name/identity”,权限不足时给出建议的新域名。
其中num_replicas为隐藏的 UNSTABLE 选项(--num-replicas),用于指定数据库副本数(L233-L238)。
发布最佳实践
开发阶段
- 早期开发中数据丢失可接受时,放心使用
--delete-data(-c=always)快速重置; - 使用
-d/--debug或单独执行spacetime build加速本地迭代; - 为开发、预发、生产分别建立独立数据库,用
spacetime.json固化各自目标。
生产阶段
- 谨慎规划 schema 变更:发布前对照自动迁移的三类兼容性规则逐条检查;
- 与客户端升级协同:涉及潜在破坏性变更时,先升级客户端再发布
--break-clients,把断连窗口降到最低; - 优先向后兼容:尽量新增表/reducer 而非修改既有结构,用增量迁移模式处理复杂变更;
- 保留数据库 identity:作为后续运维操作的定位依据。
发布之后:下一步学习
模块上线后,可以继续深入:
- 学习连接客户端 与数据库交互;
- 深入了解表、reducer 与procedure 的定义与生命周期;
- 查阅自动迁移 与增量迁移 的完整规则;
- 若使用
spacetime dev进行本地热重载开发,参考开发命令文档。
【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考