92 lines
5.1 KiB
Markdown
92 lines
5.1 KiB
Markdown
# 元数据容器与原子性部署需求
|
||
|
||
## 元数据
|
||
- 需求编号:014-4
|
||
- 创建时间:2026-01-26
|
||
- 创建人:SSOT 架构师
|
||
- 状态:已完成
|
||
- 优先级:高
|
||
- 父需求:[REQ-014](../REQ-014.md)
|
||
- 关联代码:`com.sforce.soap.tooling.MetadataContainer`, `com.sforce.soap.tooling.ContainerAsyncRequest`, `com.sforce.soap.tooling.DeployDetails`
|
||
|
||
## 需求概述
|
||
实现基于 Tooling API 的“事务原子性”代码部署模块。通过 `MetadataContainer` 机制,支持将多个 Apex 类、触发器、Visualforce 页面等成员的修改打包,一次性原子部署。此机制是 Salesforce IDE 开发的核心,确保代码依赖的一致性。
|
||
|
||
## 目标
|
||
1. **原子性保证**:多文件修改(如 Class A 引用 Class B)必须作为一个事务提交,要么全成功,要么全失败。
|
||
2. **编译与测试**:在部署过程中自动触发编译检查,并可选执行测试用例。
|
||
3. **状态反馈**:提供详细的部署结果,包括每一行的编译错误或测试失败信息。
|
||
|
||
## 功能需求
|
||
|
||
### 1. 容器生命周期管理 (Container Lifecycle)
|
||
必须处理容器名称冲突问题(MetadataContainer Name 必须唯一)。
|
||
- `createContainer(String name)`: 创建新容器。如果同名容器已存在,应先尝试删除或使用唯一后缀生成新名称。
|
||
- `deleteContainer(String id)`: 部署完成后或发生异常时,清理容器以释放资源。
|
||
|
||
### 2. 成员管理 (Member Management)
|
||
支持添加多种类型的元数据成员到容器中。
|
||
- `addMember(String containerId, String metadataType, String contentEntityId, String body)`
|
||
- **metadataType**: 支持 `ApexClassMember`, `ApexTriggerMember`, `ApexComponentMember`, `ApexPageMember`。
|
||
- **contentEntityId**: 对应 `ApexClass` 或 `ApexTrigger` 的 ID。如果是新建文件,此字段可能为空(取决于 API 版本行为,通常 Tooling API 更新需 ID)。
|
||
- **body**: 新的代码内容。
|
||
|
||
### 3. 异步部署请求 (Async Deployment)
|
||
创建 `ContainerAsyncRequest` 对象触发编译和部署。
|
||
- `deployContainer(String containerId, boolean isCheckOnly, boolean isRunTests)`
|
||
- **IsCheckOnly**: `true` 仅编译验证(不保存);`false` 实际保存代码。
|
||
- **IsRunTests**: 是否在部署后运行测试(通常用于生产环境部署或验证)。
|
||
- 返回 `requestId` (ContainerAsyncRequest ID)。
|
||
|
||
### 4. 状态轮询与结果解析 (Status Polling & Result Parsing)
|
||
由于部署是异步的,需要轮询状态并解析结果。
|
||
- `checkStatus(String requestId)`
|
||
- 轮询 `ContainerAsyncRequest` 对象的 `State` 字段。
|
||
- **状态流转**: `Queued` -> `Processing` -> `Completed` / `Failed` / `Error` / `Invalidated` / `Aborted`。
|
||
- `getDeployDetails(String requestId)`
|
||
- 当状态为 `Completed` 或 `Failed` 时,读取 `DeployDetails` 字段。
|
||
- **解析编译错误**: 遍历 `DeployDetails.getComponentFailures()` (对应 `DeployMessage` 数组),提取 `fileName`, `lineNumber`, `problem` 等信息。
|
||
- **解析测试结果**: 如果运行了测试,解析 `DeployDetails.getRunTestResult()`。
|
||
|
||
## 数据结构与接口定义
|
||
|
||
### 部署结果对象 (DeploymentResult)
|
||
```java
|
||
public class DeploymentResult {
|
||
private boolean success;
|
||
private String status; // Completed, Failed, etc.
|
||
private String errorMsg; // 系统级错误
|
||
private List<CompilationError> compilationErrors; // 代码编译错误
|
||
}
|
||
|
||
public class CompilationError {
|
||
private String fileName;
|
||
private int line;
|
||
private int column;
|
||
private String message;
|
||
}
|
||
```
|
||
|
||
## 异常处理
|
||
1. **容器名称冲突**: 捕获 `DUPLICATE_VALUE` 异常,自动重试或清理旧容器。
|
||
2. **成员添加失败**: 如 `contentEntityId` 无效或 `body` 为空,应在添加阶段报错。
|
||
3. **并发部署限制**: Salesforce 允许的并发 `ContainerAsyncRequest` 有限,需处理排队超时情况。
|
||
|
||
## 技术约束
|
||
- **DeployDetails 引用**: 必须使用 `com.sforce.soap.tooling.DeployDetails` 类进行反序列化。
|
||
- **API 版本**: 确保使用的 Tooling API 版本支持当前的元数据类型。
|
||
- **CheckOnly 限制**: `CheckOnly=true` 不会修改服务器代码,但会生成编译结果,适用于“保存前语法检查”。
|
||
|
||
## 成功标准
|
||
1. **原子性验证**: 创建一个依赖链(Class A 依赖修改后的 Class B),在同一个容器中部署成功。
|
||
2. **错误捕获**: 故意引入语法错误,部署状态应为 `Failed`,并能准确返回错误行号和错误信息。
|
||
3. **CheckOnly 模式**: 使用 `IsCheckOnly=true` 部署成功后,查询 `ApexClass` 内容确认未被修改。
|
||
|
||
## 相关文档
|
||
- [设计文档](../design/2026-01-27-014-4-元数据容器与原子性部署-设计.md)
|
||
- [决策记录](../decisions/adr/2026-01-27-014-4-ADR-元数据容器与原子性部署技术选型.md)
|
||
- [提示词文档](../prompts/2026-01-27-014-4-prompt-元数据容器与原子性部署.md)
|
||
- [变更日志](../changelog/2026-01-27-014-4-changelog.md)
|
||
- [复盘文档](../retros/2026-01-27-014-4-retro.md)
|
||
- [API 文档](../api-docs/2026-01-27-014-4-api.md)
|