- 完成REQ-010-17(性能优化和限流处理)的所有6个阶段 - 创建ADR文档:0026-performance-optimization.md - 创建Prompt文档:027-performance-optimization.md - 创建会话记录:20260119-performance-optimization.md - 创建变更记录:20260119-performance-optimization.md - 创建复盘报告:20260119-performance-optimization-retro.md - 更新index.md和CHANGELOG.md - 完成REQ-010-2(基础实体类和Mapper创建)的前3个阶段 - 更新ADR文档:0011-entity-mapper-create.md - 创建Prompt文档:002-entity-mapper-create.md - 更新index.md 所有文档均按照SSOT方法论创建,包括需求定义、架构决策、提示词资产化、执行会话、变更记录和闭环复盘。
16 KiB
16 KiB
Prompt - Quick Deploy功能实现
输入引用
引用相关的 docs 文档链接:
- REQ-010-9.md - Quick Deploy功能实现需求文档
- 0018-quick-deploy.md - Quick Deploy功能实现架构决策
- REQ-010-8.md - 元数据部署核心功能需求文档
- 0017-metadata-deploy-core.md - 元数据部署核心功能架构决策
- metadata-module.md - Salesforce Metadata API 模块说明
Context Maps
强制列出本次 Prompt 依赖的 Canvas 文件:
- Authentication.canvas - 项目架构视觉化展示
- 相关节点: 集成核心 - 提供与Salesforce的各种连接方式
- 相关节点: IMetadataApiService - 元数据API服务接口
- 相关节点: MetadataApiClient - Metadata API客户端
目标
实现 Quick Deploy 功能,包括 Quick Deploy 触发、Quick Deploy 历史记录、Quick Deploy 状态监控、Quick Deploy 结果解析。基于最近一次成功的部署记录快速重新部署,无需重新运行测试,显著提高部署速度。
输出格式
代码结构
datai-salesforce-metadata/
├── deploy/
│ ├── controller/
│ │ ├── MetadataDeployController.java
│ │ └── QuickDeployController.java
│ ├── service/
│ │ ├── IMetadataDeployService.java
│ │ ├── MetadataDeployServiceImpl.java
│ │ ├── IQuickDeployService.java
│ │ └── QuickDeployServiceImpl.java
│ ├── enums/
│ │ └── DeployStatus.java
│ ├── dto/
│ │ ├── DeployTriggerRequest.java
│ │ ├── DeployTriggerResponse.java
│ │ ├── DeployProgressResponse.java
│ │ ├── DeployHistoryResponse.java
│ │ ├── DeployResult.java
│ │ ├── QuickDeployTriggerRequest.java
│ │ ├── QuickDeployTriggerResponse.java
│ │ ├── QuickDeployProgressResponse.java
│ │ ├── QuickDeployHistoryResponse.java
│ │ └── QuickDeployResult.java
│ ├── config/
│ │ └── AsyncConfig.java
│ └── exception/
│ └── DeployException.java
代码示例(语言:Java)
1. QuickDeployController 控制器
package com.datai.salesforce.metadata.deploy.controller;
import com.datai.salesforce.metadata.deploy.dto.QuickDeployTriggerRequest;
import com.datai.salesforce.metadata.deploy.dto.QuickDeployTriggerResponse;
import com.datai.salesforce.metadata.deploy.dto.QuickDeployProgressResponse;
import com.datai.salesforce.metadata.deploy.dto.QuickDeployHistoryResponse;
import com.datai.salesforce.metadata.deploy.service.IQuickDeployService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@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 服务接口
package com.datai.salesforce.metadata.deploy.service;
import com.datai.salesforce.metadata.deploy.dto.QuickDeployTriggerRequest;
import com.datai.salesforce.metadata.deploy.dto.QuickDeployTriggerResponse;
import com.datai.salesforce.metadata.deploy.dto.QuickDeployProgressResponse;
import com.datai.salesforce.metadata.deploy.dto.QuickDeployHistoryResponse;
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 服务实现
package com.datai.salesforce.metadata.deploy.service;
import com.datai.salesforce.metadata.deploy.dto.QuickDeployTriggerRequest;
import com.datai.salesforce.metadata.deploy.dto.QuickDeployTriggerResponse;
import com.datai.salesforce.metadata.deploy.dto.QuickDeployProgressResponse;
import com.datai.salesforce.metadata.deploy.dto.QuickDeployHistoryResponse;
import com.datai.salesforce.metadata.deploy.enums.DeployStatus;
import com.datai.salesforce.metadata.deploy.exception.DeployException;
import com.datai.salesforce.metadata.entity.DataiMetaJobExecution;
import com.datai.salesforce.metadata.mapper.DataiMetaJobExecutionMapper;
import com.datai.salesforce.metadata.service.IMetadataApiService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
@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. QuickDeployTriggerRequest DTO
package com.datai.salesforce.metadata.deploy.dto;
import lombok.Data;
@Data
public class QuickDeployTriggerRequest {
private Long orgConfigId;
private String createdBy;
}
5. QuickDeployTriggerResponse DTO
package com.datai.salesforce.metadata.deploy.dto;
import lombok.Data;
@Data
public class QuickDeployTriggerResponse {
private String jobId;
private String status;
private String message;
}
6. QuickDeployProgressResponse DTO
package com.datai.salesforce.metadata.deploy.dto;
import lombok.Data;
@Data
public class QuickDeployProgressResponse {
private String jobId;
private String status;
private int progress;
private String message;
}
7. QuickDeployHistoryResponse DTO
package com.datai.salesforce.metadata.deploy.dto;
import com.datai.salesforce.metadata.entity.DataiMetaJobExecution;
import lombok.Data;
import java.util.List;
@Data
public class QuickDeployHistoryResponse {
private long total;
private int page;
private int size;
private List<DataiMetaJobExecution> records;
}
8. QuickDeployResult DTO
package com.datai.salesforce.metadata.deploy.dto;
import lombok.Data;
@Data
public class QuickDeployResult {
private String jobId;
private String status;
private String message;
private String errorMessage;
private int codeCoverage;
}
约束
技术栈限制
- 必须基于 Spring Boot 3 + MyBatis Plus + MySQL 技术栈
- 必须使用现有的 IMetadataApiService 接口进行 Salesforce API 调用
- 必须使用现有的 DataiMetaJobExecution 实体和 Mapper
架构约束
- 必须遵循 Authentication.canvas 中定义的架构和调用关系
- 必须在 datai-salesforce-metadata 模块下实现
- 必须使用 RESTful API 设计规范
性能要求
- Quick Deploy 触发响应时间 < 1s
- Quick Deploy 状态轮询任务执行时间 < 1s
- Quick Deploy 进度查询响应时间 < 500ms
- Quick Deploy 历史记录查询响应时间 < 1s
安全性要求
- Quick Deploy 操作需要认证
- 部署数据传输加密
- 敏感信息不记录到日志
Rule Set
"请严格参考 @Authentication.canvas 中的状态机转移逻辑,不要自行发挥。"
具体规则:
- 必须使用 Canvas 中定义的类名和方法名
- 必须遵循 Canvas 中定义的调用关系
- 必须参考 Canvas 中的流程图逻辑
- 必须复用现有的 DeployStatus 枚举和状态管理逻辑
- 必须复用现有的 AsyncConfig 配置类和线程池
验收标准
功能完整性
- Quick Deploy 触发成功,支持选择最近一次成功的部署记录
- Quick Deploy 验证成功,检查部署记录是否在 30 天内
- Quick Deploy 历史记录成功,支持分页查询和条件查询
- Quick Deploy 状态监控正常工作,使用状态机管理 Quick Deploy 状态
- Quick Deploy 结果解析成功,错误信息提取正确
代码正确性
- 代码符合项目编码规范,有清晰的注释
- 单元测试覆盖率 > 80%
- 集成测试通过率 100%
- 无严重的代码质量问题
文档准确性
- API 文档完整,包含接口说明、参数说明、返回值说明
- 代码注释清晰,包含方法说明、参数说明、返回值说明
- 使用文档完整,包含使用示例和注意事项
性能指标
- Quick Deploy 触发响应时间 < 1s
- Quick Deploy 状态轮询任务执行时间 < 1s
- Quick Deploy 进度查询响应时间 < 500ms
- Quick Deploy 历史记录查询响应时间 < 1s
风险
输出质量风险
- Quick Deploy 验证逻辑复杂可能导致验证不准确
- 状态监控不准确可能导致 Quick Deploy 状态不一致
- 结果解析不完善可能导致错误信息不准确
技术实现风险
- Quick Deploy 可能在某些情况下不可用
- 部署历史记录过多可能影响查询性能
- 异步任务状态跟踪困难
时间成本风险
- Quick Deploy 功能实现可能需要较长时间
- 测试和验证可能需要较长时间
- 文档编写可能需要较长时间
使用记录
| 日期 | 使用场景 | 输入参数 | 输出结果 | 反馈 | 改进措施 |
|---|---|---|---|---|---|
| 2026-01-19 | Quick Deploy功能实现 | REQ-010-9, ADR-0018 | Quick Deploy功能代码 | 待反馈 | 待改进 |