# 部署记录状态: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` 状态**,用于未来可能的手动取消部署功能。 这样既保证了语义清晰,又保留了扩展性。