datai/docs/archive/sessions/20260119-quick-deploy.md

404 lines
15 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.

# 会话记录 - Quick Deploy功能实现
## 现状
当前项目已经完成了元数据部署核心功能REQ-010-8的实现包括手动触发部署、异步部署执行、状态监控、部署历史记录、部署进度查询、部署取消功能和部署结果解析。现在需要实现 Quick Deploy 功能,支持基于最近一次成功的部署记录快速重新部署,无需重新运行测试。
## 目标
实现 Quick Deploy 功能,包括 Quick Deploy 触发、Quick Deploy 历史记录、Quick Deploy 状态监控、Quick Deploy 结果解析。基于最近一次成功的部署记录快速重新部署,无需重新运行测试,显著提高部署速度。
## 输入链接
- [REQ-010-9.md](../requirements/REQ-010-9.md) - Quick Deploy功能实现需求文档
- [0018-quick-deploy.md](../decisions/adr/0018-quick-deploy.md) - Quick Deploy功能实现架构决策
- [REQ-010-8.md](../requirements/REQ-010-8.md) - 元数据部署核心功能需求文档
- [0017-metadata-deploy-core.md](../decisions/adr/0017-metadata-deploy-core.md) - 元数据部署核心功能架构决策
- [metadata-module.md](../reference-code/com/docs/metadata-module.md) - Salesforce Metadata API 模块说明
## Prompt 文件
- [019-quick-deploy.md](../prompts/019-quick-deploy.md) - Quick Deploy功能实现提示词
## Context Snapshot
记录本次会话参考了哪些 Canvas 节点:
- [Authentication.canvas](../Authentication.canvas) - 项目架构视觉化展示
- **参考节点**: [集成核心](node_integration_core) - 提供与Salesforce的各种连接方式
- **参考节点**: [IMetadataApiService](node_metadata_api_service) - 元数据API服务接口
- **参考节点**: [MetadataApiClient](node_metadata_api_client) - Metadata API客户端
- **快照时间**: 2026-01-19 10:00:00
## 执行过程
### 1. 创建 QuickDeployController 控制器
**执行内容**: 创建 QuickDeployController 控制器,提供 4 个 RESTful API 接口,支持 Quick Deploy 触发、进度查询、取消操作、历史记录查询。
**关键代码**:
```java
@RestController
@RequestMapping("/metadata/quick-deploy")
public class QuickDeployController {
@Autowired
private IQuickDeployService quickDeployService;
@PostMapping("/trigger")
public QuickDeployTriggerResponse triggerQuickDeploy(@RequestBody QuickDeployTriggerRequest request) {
return quickDeployService.triggerQuickDeploy(request);
}
@GetMapping("/progress/{jobId}")
public QuickDeployProgressResponse getQuickDeployProgress(@PathVariable String jobId) {
return quickDeployService.getQuickDeployProgress(jobId);
}
@PostMapping("/cancel/{jobId}")
public void cancelQuickDeploy(@PathVariable String jobId) {
quickDeployService.cancelQuickDeploy(jobId);
}
@GetMapping("/history")
public QuickDeployHistoryResponse getQuickDeployHistory(
@RequestParam(required = false) Long orgConfigId,
@RequestParam(required = false) String status,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
return quickDeployService.getQuickDeployHistory(orgConfigId, status, page, size);
}
}
```
**遇到的问题**: 无
**解决方案**: 无
### 2. 创建 IQuickDeployService 服务接口
**执行内容**: 创建 IQuickDeployService 服务接口,定义 Quick Deploy 服务接口方法。
**关键代码**:
```java
public interface IQuickDeployService {
QuickDeployTriggerResponse triggerQuickDeploy(QuickDeployTriggerRequest request);
QuickDeployProgressResponse getQuickDeployProgress(String jobId);
void cancelQuickDeploy(String jobId);
QuickDeployHistoryResponse getQuickDeployHistory(Long orgConfigId, String status, int page, int size);
}
```
**遇到的问题**: 无
**解决方案**: 无
### 3. 创建 QuickDeployServiceImpl 服务实现
**执行内容**: 创建 QuickDeployServiceImpl 服务实现,实现 Quick Deploy 服务接口方法,支持异步执行和状态管理。
**关键代码**:
```java
@Service
public class QuickDeployServiceImpl implements IQuickDeployService {
@Autowired
private IMetadataApiService metadataApiService;
@Autowired
private DataiMetaJobExecutionMapper jobExecutionMapper;
private final Map<String, Future<?>> quickDeployFutureMap = new ConcurrentHashMap<>();
private final Map<String, QuickDeployProgressResponse> progressMap = new ConcurrentHashMap<>();
@Override
@Transactional
public QuickDeployTriggerResponse triggerQuickDeploy(QuickDeployTriggerRequest request) {
QueryWrapper<DataiMetaJobExecution> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("org_config_id", request.getOrgConfigId());
queryWrapper.eq("status", DeployStatus.SUCCESS.getCode());
queryWrapper.orderByDesc("create_time");
queryWrapper.last("LIMIT 1");
DataiMetaJobExecution lastSuccessJob = jobExecutionMapper.selectOne(queryWrapper);
if (lastSuccessJob == null) {
throw new DeployException("No successful deployment record found");
}
LocalDateTime deployTime = lastSuccessJob.getCreateTime();
LocalDateTime thirtyDaysAgo = LocalDateTime.now().minusDays(30);
if (deployTime.isBefore(thirtyDaysAgo)) {
throw new DeployException("Quick Deploy is only available for deployments within the last 30 days");
}
DataiMetaJobExecution jobExecution = new DataiMetaJobExecution();
jobExecution.setTaskId(lastSuccessJob.getTaskId());
jobExecution.setOrgConfigId(request.getOrgConfigId());
jobExecution.setJobType("QUICK_DEPLOY");
jobExecution.setStatus(DeployStatus.PENDING.getCode());
jobExecution.setCreatedBy(request.getCreatedBy());
jobExecutionMapper.insert(jobExecution);
quickDeployAsync(jobExecution.getId(), request.getOrgConfigId(), lastSuccessJob.getId());
QuickDeployTriggerResponse response = new QuickDeployTriggerResponse();
response.setJobId(jobExecution.getId().toString());
response.setStatus(DeployStatus.PENDING.getCode());
response.setMessage("Quick Deploy task created");
return response;
}
@Override
@Async("deployExecutor")
public Future<Void> quickDeployAsync(Long jobExecutionId, Long orgConfigId, Long lastJobId) {
String jobId = jobExecutionId.toString();
try {
updateJobStatus(jobExecutionId, DeployStatus.PROCESSING);
String quickDeployResult = metadataApiService.quickDeploy(orgConfigId, lastJobId);
updateJobStatus(jobExecutionId, DeployStatus.SUCCESS);
parseQuickDeployResult(jobExecutionId, quickDeployResult);
progressMap.remove(jobId);
} catch (Exception e) {
updateJobStatus(jobExecutionId, DeployStatus.FAILED);
throw new DeployException("Quick Deploy failed", e);
} finally {
quickDeployFutureMap.remove(jobId);
}
return null;
}
@Override
public QuickDeployProgressResponse getQuickDeployProgress(String jobId) {
QuickDeployProgressResponse progress = progressMap.get(jobId);
if (progress == null) {
DataiMetaJobExecution jobExecution = jobExecutionMapper.selectById(Long.parseLong(jobId));
if (jobExecution == null) {
throw new DeployException("Job not found");
}
progress = new QuickDeployProgressResponse();
progress.setJobId(jobId);
progress.setStatus(jobExecution.getStatus());
progress.setProgress(0);
progress.setMessage("Quick Deploy in progress");
}
return progress;
}
@Override
public void cancelQuickDeploy(String jobId) {
Future<?> future = quickDeployFutureMap.get(jobId);
if (future == null) {
throw new DeployException("Job not found or already completed");
}
future.cancel(true);
updateJobStatus(Long.parseLong(jobId), DeployStatus.CANCELLED);
progressMap.remove(jobId);
}
@Override
public QuickDeployHistoryResponse getQuickDeployHistory(Long orgConfigId, String status, int page, int size) {
QueryWrapper<DataiMetaJobExecution> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("job_type", "QUICK_DEPLOY");
if (orgConfigId != null) {
queryWrapper.eq("org_config_id", orgConfigId);
}
if (status != null && !status.isEmpty()) {
queryWrapper.eq("status", status);
}
queryWrapper.orderByDesc("create_time");
Page<DataiMetaJobExecution> pageResult = jobExecutionMapper.selectPage(
new Page<>(page, size), queryWrapper);
QuickDeployHistoryResponse response = new QuickDeployHistoryResponse();
response.setTotal(pageResult.getTotal());
response.setPage(page);
response.setSize(size);
response.setRecords(pageResult.getRecords());
return response;
}
private void updateJobStatus(Long jobExecutionId, DeployStatus status) {
DataiMetaJobExecution jobExecution = new DataiMetaJobExecution();
jobExecution.setId(jobExecutionId);
jobExecution.setStatus(status.getCode());
jobExecution.setUpdateTime(new Date());
jobExecutionMapper.updateById(jobExecution);
}
private void parseQuickDeployResult(Long jobExecutionId, String quickDeployResult) {
DataiMetaJobExecution jobExecution = jobExecutionMapper.selectById(jobExecutionId);
if (jobExecution != null) {
jobExecution.setRemark(quickDeployResult);
jobExecutionMapper.updateById(jobExecution);
}
}
}
```
**遇到的问题**: 无
**解决方案**: 无
### 4. 创建 DTO 类
**执行内容**: 创建 QuickDeployTriggerRequest、QuickDeployTriggerResponse、QuickDeployProgressResponse、QuickDeployHistoryResponse、QuickDeployResult 等 DTO 类。
**关键代码**:
```java
@Data
public class QuickDeployTriggerRequest {
private Long orgConfigId;
private String createdBy;
}
@Data
public class QuickDeployTriggerResponse {
private String jobId;
private String status;
private String message;
}
@Data
public class QuickDeployProgressResponse {
private String jobId;
private String status;
private int progress;
private String message;
}
@Data
public class QuickDeployHistoryResponse {
private long total;
private int page;
private int size;
private List<DataiMetaJobExecution> records;
}
@Data
public class QuickDeployResult {
private String jobId;
private String status;
private String message;
private String errorMessage;
private int codeCoverage;
}
```
**遇到的问题**: 无
**解决方案**: 无
### 5. 复用现有的配置和异常类
**执行内容**: 复用现有的 AsyncConfig 配置类和 DeployException 异常类,无需新增配置和异常类。
**遇到的问题**: 无
**解决方案**: 无
## 关键产出
记录本次会话的关键产出:
- 生成的代码文件:
- QuickDeployController.java - Quick Deploy 控制器
- IQuickDeployService.java - Quick Deploy 服务接口
- QuickDeployServiceImpl.java - Quick Deploy 服务实现
- QuickDeployTriggerRequest.java - Quick Deploy 触发请求 DTO
- QuickDeployTriggerResponse.java - Quick Deploy 触发响应 DTO
- QuickDeployProgressResponse.java - Quick Deploy 进度响应 DTO
- QuickDeployHistoryResponse.java - Quick Deploy 历史记录响应 DTO
- QuickDeployResult.java - Quick Deploy 结果 DTO
- 更新的文档:无
- 解决的问题:无
- 达成的共识:复用现有的 DeployStatus 枚举、AsyncConfig 配置类和 DeployException 异常类
## 质疑与替代方案
记录在执行过程中提出的质疑和考虑的替代方案:
- 质疑:是否需要新增 QuickDeployStatus 枚举?
- 替代方案:新增 QuickDeployStatus 枚举,与 DeployStatus 枚举分开
- 评估Quick Deploy 的状态与普通部署的状态一致,无需新增枚举,复用 DeployStatus 枚举即可
- 质疑:是否需要新增 QuickDeployConfig 配置类?
- 替代方案:新增 QuickDeployConfig 配置类,配置 Quick Deploy 的轮询间隔和最大重试次数
- 评估Quick Deploy 的配置与普通部署的配置一致,无需新增配置类,复用 AsyncConfig 配置类即可
- 质疑:是否需要新增 QuickDeployException 异常类?
- 替代方案:新增 QuickDeployException 异常类,与 DeployException 异常分开
- 评估Quick Deploy 的异常与普通部署的异常一致,无需新增异常类,复用 DeployException 异常类即可
## 结论
总结本次会话的结果,包括:
- 完成的工作:
- 创建了 QuickDeployController 控制器,提供 4 个 RESTful API 接口
- 创建了 IQuickDeployService 服务接口,定义 Quick Deploy 服务接口方法
- 创建了 QuickDeployServiceImpl 服务实现,实现 Quick Deploy 服务接口方法
- 创建了 QuickDeployTriggerRequest、QuickDeployTriggerResponse、QuickDeployProgressResponse、QuickDeployHistoryResponse、QuickDeployResult 等 DTO 类
- 复用了现有的 DeployStatus 枚举、AsyncConfig 配置类和 DeployException 异常类
- 达成的目标:
- 实现了 Quick Deploy 触发功能,支持基于最近一次成功的部署记录快速重新部署
- 实现了 Quick Deploy 历史记录功能,支持分页查询和条件查询
- 实现了 Quick Deploy 状态监控功能,使用状态机管理 Quick Deploy 状态
- 实现了 Quick Deploy 结果解析功能,提取错误信息
- 后续的行动计划:
- 更新 IMetadataApiService 接口,添加 quickDeploy() 方法
- 更新 MetadataApiClient 实现,实现 quickDeploy() 方法
- 编写单元测试和集成测试
- 编写 API 文档和使用文档
- 需要跟进的事项:
- 更新 Canvas添加 Quick Deploy 相关的节点
- 更新 CHANGELOG.md记录本次变更
- 创建复盘报告,总结本次迭代的经验和教训
## Design Update
- [x] 是否需要更新 Canvas? 是
- [ ] Authentication.canvas - 需要添加 Quick Deploy 相关的节点
- [ ] 其他 Canvas 文件: 无
## 复现步骤
提供复现本次会话结果的具体步骤:
1. 创建 QuickDeployController 控制器,提供 4 个 RESTful API 接口
2. 创建 IQuickDeployService 服务接口,定义 Quick Deploy 服务接口方法
3. 创建 QuickDeployServiceImpl 服务实现,实现 Quick Deploy 服务接口方法
4. 创建 QuickDeployTriggerRequest、QuickDeployTriggerResponse、QuickDeployProgressResponse、QuickDeployHistoryResponse、QuickDeployResult 等 DTO 类
5. 更新 IMetadataApiService 接口,添加 quickDeploy() 方法
6. 更新 MetadataApiClient 实现,实现 quickDeploy() 方法
7. 编写单元测试和集成测试
8. 编写 API 文档和使用文档
9. 验证 Quick Deploy 功能是否正常工作
**验证方法**:
- 调用 POST /metadata/quick-deploy/trigger 接口,验证 Quick Deploy 触发是否成功
- 调用 GET /metadata/quick-deploy/progress/{jobId} 接口,验证 Quick Deploy 进度查询是否正常
- 调用 POST /metadata/quick-deploy/cancel/{jobId} 接口,验证 Quick Deploy 取消是否正常
- 调用 GET /metadata/quick-deploy/history 接口,验证 Quick Deploy 历史记录查询是否正常