deploy-ease-platform/backend/docs/deploy-record-status-rejected-analysis.md
2025-11-04 22:37:01 +08:00

203 lines
5.8 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.

# 部署记录状态CANCELLED vs REJECTED 分析
## 当前状态
### CANCELLED已取消的使用场景
**唯一使用场景**:审批被拒绝
- 位置:`DeployRecordServiceImpl.updateStatusFromApproval()`
- 代码:`record.setStatus(DeployRecordStatusEnums.CANCELLED);`
- 日志:`"部署记录状态已更新为已取消(审批被拒)"`
**结论**:当前 `CANCELLED` 只用于审批被拒绝的场景。
### 其他状态的使用场景
| 状态 | 使用场景 | 来源 |
|------|---------|------|
| **TERMINATED** | 工作流被手动终止 | 工作流状态 `TERMINATED` |
| **FAILED** | 工作流执行失败 | 工作流状态 `FAILED` |
| **CANCELLED** | 审批被拒绝 | 审批事件 `ApprovalResultEnum.REJECTED` |
## 问题分析
### 问题1语义不清晰
**当前问题**
- `CANCELLED`(已取消)语义模糊,不能明确表示是"审批被拒绝"
- 未来如果有手动取消部署功能,会产生歧义
**对比**
- 工作流层面:`ApprovalResultEnum.REJECTED`(拒绝)
- 部署记录层面:`CANCELLED`(已取消)
- **不一致**:两个层面使用不同的语义
### 问题2未来扩展性
**未来可能的场景**
1. **手动取消部署**:用户主动取消正在运行的部署
- 应该使用什么状态?如果用 `CANCELLED`,会与"审批被拒绝"混淆
2. **超时自动取消**:部署超时自动取消
- 应该使用什么状态?
## 方案对比
### 方案A保留 CANCELLED新增 REJECTED推荐
**状态定义**
```java
public enum DeployRecordStatusEnums {
// ... 其他状态 ...
/**
* 审批被拒绝(终态)
*/
REJECTED("REJECTED", "审批被拒绝"),
/**
* 已取消(终态)
* 用于:手动取消部署、超时自动取消等场景
*/
CANCELLED("CANCELLED", "已取消"),
// ... 其他状态 ...
}
```
**优点**
1. ✅ 语义清晰:`REJECTED` 明确表示"审批被拒绝"
2. ✅ 与工作流层面保持一致:`ApprovalResultEnum.REJECTED` → `DeployRecordStatusEnums.REJECTED`
3. ✅ 保留扩展性:`CANCELLED` 可用于未来手动取消场景
4. ✅ 状态语义明确,便于理解和维护
**缺点**
- 需要新增枚举值
- 需要修改相关代码
- 需要数据库迁移(如果已有数据)
**需要修改的地方**
1. 枚举类:新增 `REJECTED`
2. `DeployRecordServiceImpl.updateStatusFromApproval()`:改为 `REJECTED`
3. `isFinalState()`:添加 `REJECTED`
4. 统计查询:`REJECTED` 计入失败计数
5. `fromWorkflowStatus()`:不需要修改(因为 `REJECTED` 不是从工作流状态转换来的)
### 方案B直接用 REJECTED 替代 CANCELLED
**状态定义**
```java
public enum DeployRecordStatusEnums {
// ... 其他状态 ...
/**
* 审批被拒绝(终态)
*/
REJECTED("REJECTED", "审批被拒绝"),
// 删除 CANCELLED
}
```
**优点**
1. ✅ 语义清晰
2. ✅ 与工作流层面保持一致
3. ✅ 简化状态模型
**缺点**
1. ❌ 失去扩展性:如果未来需要手动取消功能,需要再添加状态
2. ❌ 如果未来需要区分"审批被拒绝"和"手动取消",需要再次修改
### 方案C保持现状不推荐
**优点**
- 无需修改代码
**缺点**
1. ❌ 语义不清晰
2. ❌ 与工作流层面不一致
3. ❌ 未来扩展困难
## 推荐方案
**推荐采用方案A保留 CANCELLED新增 REJECTED**
### 理由
1. **语义清晰**
- `REJECTED`:明确表示"审批被拒绝"
- `CANCELLED`:用于"手动取消"等场景
2. **状态映射清晰**
```
审批层面ApprovalResultEnum.REJECTED
部署记录DeployRecordStatusEnums.REJECTED
```
3. **未来扩展性**
- 如果未来需要手动取消部署功能,可以直接使用 `CANCELLED`
- 如果不需要手动取消,`CANCELLED` 可以保留但不用
4. **状态完整性**
- 终态包括:`SUCCESS`、`FAILED`、`REJECTED`、`CANCELLED`、`TERMINATED`、`PARTIAL_SUCCESS`
- 语义清晰,便于理解和维护
## 实施建议
### 步骤1新增 REJECTED 枚举
```java
/**
* 审批被拒绝(终态)
*/
REJECTED("REJECTED", "审批被拒绝"),
```
### 步骤2修改审批状态更新逻辑
```java
} else {
// 审批被拒绝,更新为审批被拒绝
record.setStatus(DeployRecordStatusEnums.REJECTED);
log.info("部署记录状态已更新为审批被拒绝: id={}, workflowInstanceId={}",
record.getId(), workflowInstanceId);
}
```
### 步骤3更新终态判断
```java
private boolean isFinalState(DeployRecordStatusEnums status) {
return status == DeployRecordStatusEnums.SUCCESS
|| status == DeployRecordStatusEnums.FAILED
|| status == DeployRecordStatusEnums.REJECTED // 新增
|| status == DeployRecordStatusEnums.CANCELLED
|| status == DeployRecordStatusEnums.TERMINATED
|| status == DeployRecordStatusEnums.PARTIAL_SUCCESS;
}
```
### 步骤4更新统计查询
```sql
-- 在统计查询中REJECTED 计入失败
SUM(CASE WHEN dr.status IN ('FAILED', 'REJECTED', 'CANCELLED', 'TERMINATED', 'PARTIAL_SUCCESS')
OR (dr.status = 'CREATED' AND TIMESTAMPDIFF(MINUTE, dr.create_time, NOW()) > 30)
THEN 1 ELSE 0 END) as failedCount
```
### 步骤5数据库迁移可选
如果已有审批被拒绝的记录,状态为 `CANCELLED`,可以考虑:
- 保留现有数据(`CANCELLED` 继续表示审批被拒绝)
- 或者迁移数据(将 `CANCELLED` 迁移为 `REJECTED`
## 结论
**推荐新增 `REJECTED` 状态**,用于明确表示"审批被拒绝",与工作流层面的 `ApprovalResultEnum.REJECTED` 保持一致。
**保留 `CANCELLED` 状态**,用于未来可能的手动取消部署功能。
这样既保证了语义清晰,又保留了扩展性。