datai/datai-scenes/datai-scene-salesforce/docs/retros/2026-02-06-003-06-retro.md

336 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 复盘文档 - 检索操作
## 元数据
- 需求编号003-06
- 创建时间2026-02-06
- 创建人AI Assistant
- 状态:已完成
## 复盘概述
本次复盘对 Salesforce Metadata API 检索操作功能的开发过程进行了全面回顾。从需求定义到变更记录的每个阶段都严格按照 SSOT 流程执行,确保了代码的可追溯性和可维护性。本次开发实现了元数据异步检索、状态轮询、历史查询等功能,支持 ZIP 文件 Base64 编码返回和完整的错误处理机制。
## 目标与实际产出对比
### 目标
- 实现元数据检索功能,支持提交检索请求和获取结果
- 正确处理 Salesforce Metadata API 的异步检索流程(提交-轮询-结果)
- 实现数据库持久化,记录检索历史和状态
- 提供完整的 REST API 接口5 个接口)
- 遵循 SSOT 流程,确保所有开发活动都有文档依据
- 生成符合项目规范的代码,包含单元测试
### 实际产出
- ✅ 成功实现元数据检索功能,支持提交检索请求
- ✅ 正确处理异步检索流程,实现了状态轮询机制
- ✅ 实现了 ZIP 文件 Base64 编码返回,不存储到数据库
- ✅ 实现了异步日志记录,使用 @Async 注解
- ✅ 提供了 5 个 REST API 接口:
- `POST /salesforce/metadata/retrieve` - 提交检索请求
- `GET /salesforce/metadata/retrieve/status/{asyncId}` - 轮询检索状态
- `GET /salesforce/metadata/retrieve/check/{asyncId}` - 单次检查状态
- `GET /salesforce/metadata/retrieve/history` - 获取检索历史
- `GET /salesforce/metadata/retrieve/record/{asyncId}` - 查询检索记录
- ✅ 创建了 `datai_metadata_retrieve`13 个字段4 个索引)
- ✅ 定义了 10 个专用错误码RETRIEVE_001 ~ RETRIEVE_010
- ✅ 生成了 15+ 个代码文件9 个手动 + 6+ 个代码生成器)
- ✅ 编写了 11 个单元测试用例,覆盖成功/失败/轮询/异常场景
- ✅ 严格按照 SSOT 流程执行,每个阶段都有相应的文档
## 成功经验
### 1. 异步处理模式的成功应用
**经验描述**:针对 Salesforce Metadata API 的异步特性,设计了"提交请求-轮询状态-获取结果"的完整流程,确保了异步操作的正确处理。
**具体实现**
```java
// 提交检索请求
public AsyncResult retrieveMetadata(RetrieveRequest request) {
MetadataConnection connection = connectionFactory.getConnection("source");
AsyncResult asyncResult = connection.retrieve(sfRequest);
recordRetrieveRequest(asyncResult); // 记录到数据库
return asyncResult;
}
// 轮询状态直到完成
public RetrieveResultVo pollRetrieveResult(String asyncId, long interval, long timeout) {
long startTime = System.currentTimeMillis();
while (System.currentTimeMillis() - startTime < timeout) {
RetrieveResultVo result = checkRetrieveStatus(asyncId);
if (Boolean.TRUE.equals(result.getDone())) {
return result;
}
Thread.sleep(interval);
}
throw new SalesforceOperationException("RETRIEVE_003", "检索操作超时");
}
```
**带来的好处**
- 正确处理 Salesforce 异步 API 的特性
- 提供了灵活的状态查询机制
- 支持超时控制,防止无限等待
### 2. 代码生成器与手动实现的良好结合
**经验描述**:在阶段 6 中,先使用代码生成器生成基础 CRUD 代码Entity、Mapper、基础 Service然后手动实现业务逻辑代码DTO、VO、业务 Service、Controller。这种方式既保证了代码的规范性又满足了业务需求。
**具体实践**
- 代码生成器生成了 `DataiMetadataRetrieve` Entity、`DataiMetadataRetrieveMapper` 等基础代码
- 手动实现了 `RetrieveRequest` DTO包含复杂的嵌套结构、`RetrieveResultVo` VO、`IMetadataRetrieveService` 接口和 `MetadataRetrieveServiceImpl` 实现
- 手动实现了 `MetadataRetrieveController` 提供 REST API 接口
**带来的好处**
- 减少了重复劳动,提高了开发效率
- 保证了基础代码的规范性和一致性
- 业务逻辑代码更加清晰、可维护
### 3. 复杂 DTO 结构的设计
**经验描述**`RetrieveRequest` DTO 包含了复杂的嵌套结构Unpackaged、PackageTypeMember通过合理的设计实现了与 Salesforce API 的映射。
**具体实现**
```java
@Data
@Schema(description = "检索请求")
public class RetrieveRequest implements Serializable {
private Double apiVersion;
private Boolean singlePackage;
private Unpackaged unpackaged; // 嵌套结构
private String[] packageNames;
private String[] specificFiles;
@Data
public static class Unpackaged implements Serializable {
private List<PackageTypeMember> types; // 嵌套列表
}
@Data
public static class PackageTypeMember implements Serializable {
private String name;
private String[] members;
}
}
```
**带来的好处**
- 清晰表达了 Salesforce RetrieveRequest 的结构
- 支持复杂的元数据类型配置
- 便于前端理解和使用
### 4. 完整的错误码体系
**经验描述**:定义了 10 个专用错误码,覆盖了检索操作的各种异常情况,便于问题定位和错误处理。
**错误码设计**
- RETRIEVE_001 ~ RETRIEVE_010涵盖认证失败、操作失败、超时、参数错误等各种场景
- 每个错误码都有明确的含义和处理建议
- 错误码与异常类型对应,便于统一处理
**带来的好处**
- 提高了错误处理的规范性
- 便于前端展示友好的错误信息
- 有利于问题定位和排查
### 5. 异步日志记录的性能优化
**经验描述**:使用 Spring 的 `@Async` 注解实现异步日志记录,避免日志写入阻塞主业务流程,提高了 API 响应速度。
**具体实现**
```java
@Async("threadPoolTaskExecutor")
public void recordRetrieveRequestAsync(AsyncResult asyncResult) {
// 异步记录检索历史
}
```
**带来的好处**
- 主业务流程不被日志写入阻塞
- 提高了 API 响应速度
- 解耦了业务逻辑和日志记录
## 改进点
### 1. ZIP 文件处理可以更加灵活
**问题描述**:当前实现将 ZIP 文件内容 Base64 编码后直接返回,对于大文件可能会导致内存问题。
**改进建议**
- 考虑支持流式下载,避免内存占用过高
- 可以添加 ZIP 文件大小限制和分片下载支持
- 考虑将大 ZIP 文件临时存储到文件系统或对象存储
**优先级**:中
**计划时间**:下一个迭代
### 2. 检索历史查询可以支持更多筛选条件
**问题描述**:当前的检索历史查询只支持按数量限制返回,不支持按时间范围、状态等条件筛选。
**改进建议**
- 添加时间范围筛选(开始时间、结束时间)
- 添加状态筛选Pending、InProgress、Succeeded、Failed
- 添加用户筛选(按操作用户查询)
- 支持分页查询
**优先级**:中
**计划时间**:下一个迭代
### 3. 单元测试可以覆盖更多边界场景
**问题描述**:当前的单元测试主要覆盖了正常场景和常见异常场景,对于一些边界场景(如超长 asyncId、特殊字符等覆盖不足。
**改进建议**
- 添加边界值测试(如 asyncId 长度限制)
- 添加特殊字符处理测试
- 添加并发场景测试
- 添加性能测试(大 ZIP 文件处理)
**优先级**:低
**计划时间**:技术债清理阶段
## 问题分析
### 问题 1DTO 与 Salesforce API 对象的转换逻辑较复杂
**问题描述**`RetrieveRequest` 需要转换为 Salesforce 的 `RetrieveRequest` 对象,转换逻辑涉及多个字段和嵌套结构,代码较复杂。
**根因分析**
- Salesforce API 对象结构复杂
- 需要处理可选字段和默认值
- 嵌套结构的递归转换
**解决方案**
- 使用 MapStruct 等映射工具自动生成转换代码
- 将转换逻辑抽取到单独的 Converter 类中
- 添加详细的注释说明每个字段的映射关系
**状态**:已记录,待下一个迭代优化
### 问题 2轮询间隔和超时时间的配置不够灵活
**问题描述**:当前的轮询间隔和超时时间是硬编码的,无法根据不同场景灵活调整。
**根因分析**
- 硬编码参数缺乏灵活性
- 没有考虑不同元数据类型的检索时间差异
**解决方案**
- 将轮询间隔和超时时间配置化application.yml
- 支持在请求参数中指定超时时间
- 根据元数据类型动态调整超时时间
**状态**:已记录,待下一个迭代优化
## 行动计划
| 序号 | 行动项 | 责任人 | 计划时间 | 优先级 |
|------|--------|--------|----------|--------|
| 1 | 优化 ZIP 文件处理,支持流式下载 | 开发团队 | 下一个迭代 | 中 |
| 2 | 扩展检索历史查询功能,支持更多筛选条件 | 开发团队 | 下一个迭代 | 中 |
| 3 | 增强单元测试覆盖,添加边界场景测试 | 开发团队 | 技术债清理 | 低 |
| 4 | 使用 MapStruct 优化 DTO 转换逻辑 | 开发团队 | 下一个迭代 | 中 |
| 5 | 将轮询参数配置化,支持动态调整 | 开发团队 | 下一个迭代 | 低 |
## 提取模式
### 有效的 Prompt 技巧
#### 1. 引用真源确保一致性
**技巧描述**在提示词开头明确引用需求文档、设计文档、ADR 文档等真源,确保生成的代码符合需求和设计要求。
**应用示例**
```
请基于以下真源文档实现检索操作功能:
- 需求文档docs/requirements/sub/2026-01-28-003-06-检索操作.md
- 设计文档docs/design/2026-02-03-003-06-检索操作-设计.md
- ADR 文档docs/decisions/2026-02-03-003-06-ADR-检索操作技术选型.md
```
**效果**
- 生成的代码符合需求和设计要求
- 减少了返工和修改的次数
- 提高了代码的准确性和一致性
#### 2. 详细的输出格式要求
**技巧描述**:在提示词中明确指定需要生成的文件、路径、格式等,可以提高生成代码的准确性和规范性。
**应用示例**
```
请生成以下代码文件:
1. RetrieveRequest.java - 位于 model/dto/ 包下,包含 Unpackaged 和 PackageTypeMember 内部类
2. RetrieveResultVo.java - 位于 model/vo/ 包下,包含 fromSalesforceResult 转换方法
3. IMetadataRetrieveService.java - 位于 service/ 包下,定义 retrieveMetadata、pollRetrieveResult、checkRetrieveStatus 等方法
```
**效果**
- 生成的代码结构清晰、规范
- 减少了手动调整的工作量
- 提高了代码的可维护性
#### 3. 分步骤生成复杂代码
**技巧描述**:对于复杂的业务逻辑,分步骤生成代码,先生成接口和 DTO再生成实现类最后生成单元测试。
**应用示例**
```
第一步:生成 DTO 和 VO 类
第二步:生成 Service 接口
第三步:生成 Service 实现类
第四步:生成 Controller 类
第五步:生成单元测试类
```
**效果**
- 每个步骤的代码更加聚焦和清晰
- 便于逐步验证和调整
- 减少了整体出错的可能性
### 避免的坑
#### 1. 不要忽略异步操作的特性
**坑描述**Salesforce Metadata API 的检索操作是异步的,如果忽略这一点,可能会导致状态查询失败或结果获取不完整。
**避免方法**
- 在需求分析阶段明确识别异步操作特性
- 设计完整的状态轮询机制
- 添加超时控制和错误处理
#### 2. 不要在数据库中存储大文件内容
**坑描述**:将 ZIP 文件内容存储到数据库中会导致数据库性能问题和存储空间浪费。
**避免方法**
- 在 ADR 阶段明确决策不存储 ZIP 文件到数据库
- 使用 Base64 编码在 API 响应中返回
- 考虑使用对象存储或文件系统存储大文件
#### 3. 不要硬编码配置参数
**坑描述**:硬编码轮询间隔、超时时间等参数会导致系统缺乏灵活性,无法适应不同场景。
**避免方法**
- 将配置参数抽取到 application.yml
- 支持在请求参数中动态指定
- 添加合理的默认值和校验逻辑
## 模板迭代
### 当前模板的不足
经过本次复盘,发现当前的提示词模板在以下方面可以改进:
1. **异步操作处理**:模板中缺少对异步操作特性的明确说明和处理建议
2. **大文件处理**:模板中缺少对大文件处理的指导(如 ZIP 文件、图片等)
3. **配置参数管理**:模板中缺少对配置参数管理的建议(如轮询间隔、超时时间等)
### 模板更新计划
计划在下一个迭代中更新以下模板:
1. **更新代码生成提示词模板**`docs/Prompt/0000-template.md`
- 增加异步操作处理章节
- 增加大文件处理指导
- 增加配置参数管理建议
2. **更新 DTO 设计模板**
- 增加嵌套结构 DTO 的设计示例
- 增加与外部 API 对象映射的指导
3. **更新单元测试模板**
- 增加异步操作的测试示例
- 增加边界场景测试的检查清单
## 相关文档
- [需求文档](../requirements/sub/2026-01-28-003-06-检索操作.md)
- [设计文档](../design/2026-02-03-003-06-检索操作-设计.md)
- [决策记录](../decisions/2026-02-03-003-06-ADR-检索操作技术选型.md)
- [变更日志](../changelog/2026-02-06-003-06-changelog.md)
- [API 文档](../api-docs/2026-02-06-003-06-api.md)
- [会话记录](../sessions/2026-02-03-003-06-session.md)