# 构建并部署 Hosted Service

面向开发者和 AI 的 Hosted Service 标准流程：发布主线项目版本，再部署到目标环境。

Hosted Service 用于把工作区中的后端项目构建成可重复部署的制品，并部署到一个或多个运行环境。

首次使用前建议先阅读 [Hosted Service、Environment、Slot、Endpoint 与数据库](/development/backend-development/hosted-services-and-databases/)，其中说明了资源关系与计费边界。

本文是 Hosted Service 使用流程的文档来源。具体调用参数以当前工作区 Runtime 中由 Bundle
物化的模块方法定义为准，不要把市场版本号、模块版本 ID 或内部服务地址写进自动化流程。

版本使用严格 SemVer，并与 `Cargo.toml` 的 `package.version` 完全一致。首次请求固定源码；失败、取消或请求中断后的重试沿用原版本来源，主线变化不会换源。修改源码必须发布新版本。SHA 只用于内部来源追溯，不再作为构建输入。

## 核心契约

版本发布和环境部署是两个独立阶段：

```text
Project + 指定 Cargo package.version
  -> Release Operation
  -> immutable hosted_service_release
  -> Hosted Service Environment Deployment
```

- `Release Operation` 接受项目和显式 `--version`，首次校验根 `Cargo.toml` 的 `package.version` 并固定主线源码，并记录状态和失败原因。
- 发布成功后登记不可变 `hosted_service_release`；Artifact Service 仍是制品元数据的所有者。
- Hosted Service 部署只接收 `projectId + projectVersion`，不接收 `releaseOperationId`、`buildJobId` 或
  `artifactId`，也不会隐式触发构建。
- 项目以 `hosted-service.toml` 声明运行入口和 Endpoint；发布结果包含
  `hosted-service.manifest.json` 与项目版本发布清单。
- `hosted-service.toml` 的可复制模板、字段约束及 CLI `manifest schema/init/validate` 命令见
  [构建制品并部署](/development/backend-development/build-and-deploy/)。
- 同一个 `projectVersion` 可以部署到开发、测试、生产等多个环境，也可以用于回滚。
- 相同 Project 的同一版本只能绑定一个主线 commit；源码变化后必须提升 `package.version` 再发布。

## AI 调用前先发现当前方法

AI 或自动化程序应先查询当前运行时的服务和方法定义，再按方法定义组装参数：

1. 查找 `workspace-hosted-service`，确认项目版本发布、发布状态、Environment、配置绑定和版本部署方法。
2. 需要审计底层制品时，再查找 `workspace-artifact` 的查询方法。
3. 读取本机 `baijimu hosted-service project --help`，确认当前 CLI 的精确命令和参数。
4. 使用运行时返回的 `methodDefinition`，不要根据本文猜测可选参数。
5. 不要硬编码模块版本 ID、服务内部 URL 或历史接口路径。

本文负责解释流程和不变量；当前运行时的方法定义负责提供精确请求结构。这可以避免文档、Skill、模块版本和 Bundle 版本之间出现重复契约。

## 第一步：准备项目

构建前确认：

- 项目属于当前工作区，并且已经保存需要构建的源代码。
- Rust 项目能够在平台构建环境中执行测试和构建命令。
- 需要部署的二进制路径明确。
- 密钥、数据库密码和环境差异配置不写入源代码或 Artifact。

## 第二步：发布项目版本

先把待发布源码合并到平台 Project 主线，并把根 `Cargo.toml` 的 `package.version` 设置为本次发布版本。然后
调用项目版本发布能力；CLI 示例：

```bash
baijimu hosted-service project release <projectId> \
  --workspace-id <workspaceId> \
  --version <projectVersion> \
  --json
```

调用成功只表示 Release Operation 已创建，不表示项目版本已经发布，更不表示已经部署。

## 第三步：等待构建完成

使用返回的 `releaseOperationId` 轮询：

```bash
baijimu hosted-service project release-status <releaseOperationId> \
  --workspace-id <workspaceId> \
  --json
```

- 发布未结束时继续轮询，不要发起部署。
- 发布失败时读取 Operation 的错误消息；修复源码后，若内容变化则提升版本并重新合并主线。
- 发布成功后记录返回的 `projectVersion`、`sourceCommitId` 和底层 `artifactId`。

部署参数使用 `projectVersion`，不要把 `releaseOperationId` 或底层 `artifactId` 当成版本。

## 第四步：准备 Hosted Service 和环境

部署前确保目标 Hosted Service 和环境已经存在。根据当前方法定义，可以创建或查询：

- Hosted Service；
- 服务环境；
- 配置 Provider；
- 环境配置绑定。

数据库配置遵守独立边界：工作区先用共享积分购买 Database Instance，再在实例中创建 Logical Database；Hosted Service Environment 只保存对逻辑数据库 Profile/Allocation 的可选绑定。Environment 和绑定不收费，数据库实例按已发布 POINT 价格独立扣费。不要让构建阶段决定生产、测试或开发环境使用哪个数据库。

数据库实例的云厂商和网络位置由数据库服务的默认 Provider Placement 决定，并在购买预留时冻结；这些配置不挂在 Kubernetes 集群或 Hosted Service Environment 上。

环境变量、凭据和 Provider 绑定在部署时解析，不应打进 Artifact。

## 第五步：部署项目版本

调用当前项目版本部署方法，传入：

- 当前 `projectId`；
- 目标 `environmentId`；
- 已成功发布的 `projectVersion`。

示意调用：

```bash
baijimu hosted-service project deploy-version <projectId> \
  --workspace-id <workspaceId> \
  --environment-id <environmentId> \
  --version <projectVersion> \
  --json
```

禁止传入：

- `releaseOperationId` 或 `buildJobId`；
- `artifactId`、任意下载地址或本地文件路径来代替项目版本；
- 未成功发布或属于其他 Project 的版本。

## 第六步：等待部署并验证

部署请求返回后，使用当前运行时提供的部署查询方法检查状态，例如按项目查询部署记录或查询 Hosted Service 状态。

验证至少包括：

- deployment 最终状态为运行中；
- deployment 记录中的 `projectVersion` 是本次选择的版本；
- 主 endpoint 已生成稳定访问地址；
- 健康检查通过；
- 真实业务请求返回正确结果；
- 失败时 `message` 和日志能直接说明配置解析、容器启动或健康检查问题。

部署失败不会改变已发布版本。修复环境配置后，可以重新部署同一个 `projectVersion`。历史
`rust_binary`、`rust_bundle` 和 `hosted_service_bundle` 必须从项目主线发布为新的
`hosted_service_release` 版本后再部署。

## 作为模块后端调用 Runtime 服务

Hosted Service 如果同时是模块方法的外部后端，并通过新插件协议按需解析的地址和凭据调用
同一 Runtime 中的其他服务，需要分别处理以下身份与授权：

- 环境或安装身份用于保护本 Hosted Service 的入站 Endpoint；
- 引用解析返回的 `token` 授权当前来源服务调用绑定的目标服务及方法；
- 当前请求的 `X-Runtime-Actor-Assertion` 传递已验证最终用户。

后端在每个出站 ServiceReference 请求中发送 Bearer token；入站存在 Actor assertion 时，再原样发送该
Header。它不能解析、记录、持久化或放入异步任务。服务链进入下一目标后，由 Runtime 为下一目标后端轮换
新的 assertion，Hosted Service 不签名。完整协议见
[模块服务间调用协议](/development/bundle-development/module-development/service-to-service-calls/)和
[Runtime 用户委托](/development/bundle-development/module-development/actor-delegation/)。

## 常见错误

### 把发布操作或 Artifact 当成版本

现象：部署参数使用 `releaseOperationId`、`buildJobId` 或 `artifactId`，或者发布尚未成功就开始部署。

处理：等待 Release Operation 成功，取得真正的 `projectVersion` 后调用 `deploy-version`。

### 每个环境都重新构建

现象：开发、测试和生产环境分别产生内容不确定的新制品。

处理：同一版本只发布一次，把同一个 `projectVersion` 逐级部署到不同环境。

### 把环境配置打进制品

现象：数据库地址、Token 或生产配置写入源码或构建命令。

处理：使用 Hosted Service 环境配置和 Provider 绑定，在部署阶段解析配置。

### 只看请求成功，不看最终状态

现象：创建 Release Operation 或 deployment 后立即认为发布完成。

处理：分别轮询 Release Operation 和 deployment，直到进入最终状态，并执行 endpoint 健康和业务验证。

### Secret 已更新但进程仍返回旧鉴权结果

现象：环境 Secret 已更新，但业务请求仍由更新前启动的进程处理，例如接口继续返回 401。

处理：Secret 更新不会改写已经运行的进程环境。通过平台支持的重启操作，或者重新部署已发布的项目版本，
然后重新验证进程、健康检查和真实业务请求。不要把 Secret 写入源码或 Artifact。

### 版本尚未发布

现象：`deploy-version` 返回项目版本不存在或尚未发布。

处理：确认目标代码和 `Cargo package.version` 已在 Project 主线 HEAD，执行 `project release` 并等待成功。
旧 `hosted_service_bundle` 不能直接部署，不要恢复 `deploy-artifact`。

## 文档与版本治理

Hosted Service 的契约按以下优先级使用：

1. 本页：稳定工作流、资源边界和错误处理原则。
2. 当前运行时方法定义：当前已安装版本的精确参数、返回值和方法描述。
3. Release Operation、Artifact、deployment 各自 owner 返回的记录：一次实际执行的状态来源。

Skill 可以引导 AI 搜索本页或查询运行时方法，但不应复制整套接口定义。平台接口发生不兼容变更时，应在发布引用该能力的新模块版本和 Bundle 版本时同步更新本页。
