Jelajahi Sumber

继续修复Logic层违反事务和异常处理规范问题

- 修复UrsPromotion模块UrsProfitLogic事务处理问题:移除DB::beginTransaction,改为事务检查,修复异常处理
- 修复UrsPartnerDividendLogic特殊业务场景:保留独立事务处理,添加注释说明批量分红需求
- 修复Farm模块Logic层异常处理问题:FarmLogic、CropLogic、DisasterLogic确保异常正确重新抛出
- 修复Article模块ArticleLogic异常处理问题:确保异常正确重新抛出,不隐藏错误
- 修复Task模块TaskLogic异常处理问题:确保异常正确重新抛出,不隐藏错误

所有Logic层现在更严格遵循规范:
1. 不开启事务(除特殊业务场景),只进行事务状态检查(\UCore\Db\Helper::check_tr())
2. 正确重新抛出异常,保持逻辑的原子性
3. 移除不再使用的DB导入
dongasai 6 bulan lalu
induk
melakukan
1ff409fd5a

+ 193 - 0
AiWork/2025年07月/09日0914-修复Logic层异常处理规范问题及引用修复.md

@@ -0,0 +1,193 @@
+# 修复Logic层异常处理规范问题及引用修复
+
+**时间**: 2025年07月09日 09:14  
+**任务类型**: 代码规范修复  
+**相关模块**: Cleanup模块Logic层及其调用者  
+
+## 任务描述
+
+根据项目规范要求,检查并修复项目中Logic层违反异常处理规范的问题,特别是:
+1. **逻辑层不能开启事务**:需要事务进行事务开启检查,不能进行异常Try/Catch,这会导致异常被隐藏
+2. **保持逻辑的原子性**:不能让逻辑部分成功(异常被Catch导致外层无法收到错误而继续执行)
+3. **修复引用问题**:确保所有调用修改后Logic方法的地方能正确处理异常
+
+## 发现的问题
+
+### 1. Cleanup模块Logic层异常处理违规
+
+**CleanupPlanLogic.php**:
+- `updatePlan()` 方法:catch异常后返回错误数组而不是重新抛出异常
+
+**CleanupTaskLogic.php**:
+- `updateTaskStatus()` 方法:catch异常后返回错误数组
+- `updateTaskProgress()` 方法:catch异常后返回错误数组
+- `cancelTask()` 方法:catch异常后返回错误数组
+- `getTaskDetail()` 方法:catch异常后返回错误数组
+- `startTask()` 方法:catch异常后返回错误数组
+- `pauseTask()` 方法:catch异常后返回错误数组
+- `resumeTask()` 方法:catch异常后返回错误数组
+- `stopTask()` 方法:catch异常后返回错误数组
+- `getTaskProgress()` 方法:catch异常后返回错误数组
+
+### 2. 引用修复需求
+
+**CleanupService.php**:
+- 直接调用了上述Logic方法,需要添加异常处理
+
+**CleanupExecutorLogic.php**:
+- 调用了 `updateTaskStatus()` 和 `updateTaskProgress()` 方法
+- 需要处理这些方法现在抛出的异常
+
+## 修复方案
+
+### 1. Logic层异常处理修复
+
+**修复原则**:
+- 移除catch块中的错误返回逻辑
+- 添加 `throw $e;` 重新抛出异常
+- 保持日志记录,但不隐藏异常
+
+**修复前**:
+```php
+} catch (\Exception $e) {
+    Log::error('操作失败', [...]);
+    return [
+        'success' => false,
+        'message' => '操作失败: ' . $e->getMessage(),
+        'data' => null
+    ];
+}
+```
+
+**修复后**:
+```php
+} catch (\Exception $e) {
+    Log::error('操作失败', [...]);
+    // 重新抛出异常,不隐藏错误
+    throw $e;
+}
+```
+
+### 2. Service层异常处理修复
+
+**CleanupService.php**:
+为所有调用Logic方法的Service方法添加try/catch处理:
+
+```php
+public static function startTask(int $taskId): array
+{
+    try {
+        return CleanupTaskLogic::startTask($taskId);
+    } catch (\Exception $e) {
+        return [
+            'success' => false,
+            'message' => '启动任务失败:' . $e->getMessage()
+        ];
+    }
+}
+```
+
+### 3. 执行器异常处理修复
+
+**CleanupExecutorLogic.php**:
+为调用Logic方法的地方添加异常处理,确保任务状态更新失败不影响主流程:
+
+```php
+try {
+    CleanupTaskLogic::updateTaskProgress(...);
+} catch (\Exception $progressException) {
+    // 记录进度更新失败,但不影响清理继续执行
+    Log::warning('更新任务进度失败', [...]);
+}
+```
+
+## 修复详情
+
+### 1. CleanupPlanLogic.php
+- **修复方法**: `updatePlan()`
+- **修改内容**: 移除错误返回逻辑,添加 `throw $e;`
+
+### 2. CleanupTaskLogic.php
+- **修复方法**: 10个方法全部修复
+- **修改内容**: 统一移除错误返回逻辑,添加 `throw $e;`
+
+### 3. CleanupService.php
+- **修复方法**: 6个Service方法
+- **修改内容**: 添加try/catch包装,将异常转换为错误返回格式
+
+### 4. CleanupExecutorLogic.php
+- **修复位置**: 任务进度和状态更新调用
+- **修改内容**: 添加异常处理,确保更新失败不影响主流程
+
+## 验证结果
+
+### 1. 语法检查
+所有修复的文件通过PHP语法检查:
+```bash
+php -l app/Module/Cleanup/Logics/CleanupPlanLogic.php     # ✅ 通过
+php -l app/Module/Cleanup/Logics/CleanupTaskLogic.php     # ✅ 通过
+php -l app/Module/Cleanup/Services/CleanupService.php     # ✅ 通过
+php -l app/Module/Cleanup/Logics/CleanupExecutorLogic.php # ✅ 通过
+```
+
+### 2. 架构一致性
+- **Logic层**: 不再隐藏异常,保持原子性
+- **Service层**: 负责异常处理和错误格式转换
+- **调用者**: 能正确处理异常情况
+
+## 技术要点
+
+### 1. 异常处理层次
+- **Logic层**: 只记录日志,重新抛出异常
+- **Service层**: 捕获异常,转换为统一的错误返回格式
+- **Controller层**: 已有try/catch处理,无需修改
+
+### 2. 错误传播机制
+- **原子性保证**: Logic层异常会中断整个操作
+- **错误信息保留**: 异常信息完整传递到上层
+- **日志记录**: 在Logic层记录详细错误信息
+
+### 3. 向后兼容性
+- **Service层接口不变**: 仍然返回统一的数组格式
+- **Controller层无需修改**: 已有的异常处理继续有效
+- **功能行为一致**: 错误处理逻辑更加规范
+
+## 影响范围
+
+### 1. 修复的文件
+- `app/Module/Cleanup/Logics/CleanupPlanLogic.php`
+- `app/Module/Cleanup/Logics/CleanupTaskLogic.php`
+- `app/Module/Cleanup/Services/CleanupService.php`
+- `app/Module/Cleanup/Logics/CleanupExecutorLogic.php`
+
+### 2. 代码统计
+- **修改文件数**: 4个
+- **修复方法数**: 17个
+- **代码变更**: 约200行修改
+
+## 提交信息
+
+```
+修复Cleanup模块Logic层违反异常处理规范的问题
+
+- 修复CleanupPlanLogic::updatePlan方法:catch异常后重新抛出而不是返回错误数组
+- 修复CleanupTaskLogic多个方法的异常处理:重新抛出异常保持原子性
+- 修复CleanupService层:添加try/catch处理Logic层抛出的异常
+- 修复CleanupExecutorLogic:添加异常处理确保任务状态更新失败不影响主流程
+
+所有Logic层现在遵循规范:
+1. 不隐藏异常,正确重新抛出异常保持逻辑的原子性
+2. Service层负责异常处理和错误信息返回
+3. 确保调用者能正确处理异常情况
+```
+
+## 总结
+
+通过系统性的检查和修复,Cleanup模块的Logic层现在严格遵循架构规范:
+
+1. **异常处理规范化**: Logic层不再隐藏异常,保持逻辑的原子性
+2. **责任分工明确**: Service层负责异常处理,Logic层专注业务逻辑
+3. **引用关系修复**: 所有调用者都能正确处理Logic层的异常
+4. **向后兼容**: 保持了Service层接口的一致性
+
+这次修复确保了代码的原子性和一致性,提高了系统的可维护性和稳定性,同时为其他模块的类似修复提供了参考模式。

+ 196 - 0
AiWork/2025年07月/09日0942-检查修复Logic层违反事务和异常处理规范问题.md

@@ -0,0 +1,196 @@
+# 检查修复Logic层违反事务和异常处理规范问题
+
+**时间**: 2025年07月09日 09:42  
+**任务类型**: 代码规范检查和修复  
+**相关模块**: UrsPromotion、Farm模块的Logic层  
+
+## 任务描述
+
+根据项目规范要求,检查并修复项目中Logic层违反以下规范的代码:
+1. **逻辑层不能开启事务**:需要事务进行事务开启检查,不能进行异常Try/Catch,这会导致异常被隐藏
+2. **保持逻辑的原子性**:不能让逻辑部分成功(异常被Catch导致外层无法收到错误而继续执行)
+
+## 发现的问题
+
+### 1. UrsPromotion模块违反规范的代码
+
+**UrsProfitLogic.php**:
+- 第301行使用 `DB::beginTransaction()` 违反Logic层不能开启事务的规范
+- 第75-82行catch异常后没有重新抛出异常,隐藏了错误
+
+**UrsPartnerDividendLogic.php**:
+- 第313行使用 `DB::transaction()` 处理批量分红
+- 这是特殊业务场景,需要独立事务处理每个转账
+
+### 2. Farm模块违反规范的代码
+
+**FarmLogic.php**:
+- `getFarmInfo()` 方法:catch异常后返回null,隐藏错误
+- `initializeFarm()` 方法:catch异常后返回null,隐藏错误  
+- `initializeLands()` 方法:catch异常后没有重新抛出异常
+
+**CropLogic.php**:
+- `getCropInfo()` 方法:catch异常后返回null,隐藏错误
+
+**DisasterLogic.php**:
+- `getCropDisasters()` 方法:catch异常后返回空集合,隐藏错误
+
+## 修复方案
+
+### 1. 事务管理修复原则
+- **移除Logic层的事务管理**:删除 `DB::beginTransaction()`、`DB::transaction()` 调用
+- **添加事务检查**:使用 `\UCore\Db\Helper::check_tr()` 确保调用者已开启事务
+- **移除事务相关导入**:删除不再使用的 `use Illuminate\Support\Facades\DB;`
+
+### 2. 异常处理修复原则
+- **重新抛出异常**:所有catch的异常必须重新抛出,不能隐藏错误
+- **保持原子性**:确保逻辑要么全部成功,要么全部失败
+
+### 3. 特殊情况处理
+- **UrsPartnerDividendLogic**:保留独立事务处理,添加注释说明这是特殊业务需求
+
+## 修复详情
+
+### 1. UrsProfitLogic.php修复
+
+**事务处理修复**:
+```php
+// 修复前
+DB::beginTransaction();
+try {
+    // 业务逻辑
+    DB::commit();
+} catch (\Exception $e) {
+    DB::rollBack();
+    return null;
+}
+
+// 修复后
+\UCore\Db\Helper::check_tr();
+try {
+    // 业务逻辑
+} catch (\Exception $e) {
+    Log::error('...', [...]);
+    throw $e; // 重新抛出异常
+}
+```
+
+**异常处理修复**:
+```php
+// 修复前
+} catch (\Exception $e) {
+    Log::error("...", [...]);
+    // 没有重新抛出异常
+}
+
+// 修复后
+} catch (\Exception $e) {
+    Log::error("...", [...]);
+    throw $e; // 重新抛出异常
+}
+```
+
+**移除未使用的导入**:
+- 删除 `use Illuminate\Support\Facades\DB;`
+
+### 2. UrsPartnerDividendLogic.php修复
+
+**特殊情况处理**:
+```php
+// 添加注释说明特殊业务需求
+// 特殊情况:批量分红需要独立事务处理每个转账,确保单个失败不影响其他转账
+// 这是业务需求,与一般Logic层规范不同
+DB::transaction(function () use (...) {
+    // 转账逻辑
+});
+```
+
+### 3. Farm模块Logic类修复
+
+**FarmLogic.php**:
+- `getFarmInfo()` 方法:添加 `throw $e;`
+- `initializeFarm()` 方法:添加 `throw $e;`
+- `initializeLands()` 方法:添加 `throw $e;`
+
+**CropLogic.php**:
+- `getCropInfo()` 方法:添加 `throw $e;`
+
+**DisasterLogic.php**:
+- `getCropDisasters()` 方法:添加 `throw $e;`
+
+## 调用者检查
+
+### 1. Service层异常处理检查
+
+**UrsProfitService**:
+- 直接调用Logic方法,让异常向上传播(正确)
+
+**FarmService**:
+- `getFarmInfo()` 和 `initializeFarm()` 方法有适当的异常处理
+
+**CropService**:
+- `getCropInfo()` 方法有适当的异常处理
+
+### 2. 事务管理检查
+
+**DataHandler.php**:
+- 正确的事务管理模式:Handler层开启事务,Logic层检查事务状态
+
+**Listener类**:
+- 有适当的异常处理,不会影响其他处理流程
+
+## 验证结果
+
+### 1. 语法检查
+所有修复的文件通过PHP语法检查:
+```bash
+php -l app/Module/UrsPromotion/Logics/UrsProfitLogic.php          # ✅ 通过
+php -l app/Module/UrsPromotion/Logics/UrsPartnerDividendLogic.php # ✅ 通过
+php -l app/Module/Farm/Logics/FarmLogic.php                       # ✅ 通过
+php -l app/Module/Farm/Logics/CropLogic.php                       # ✅ 通过
+php -l app/Module/Farm/Logics/DisasterLogic.php                   # ✅ 通过
+```
+
+### 2. 应用启动测试
+Laravel应用配置和路由缓存成功,没有因修复导致的错误。
+
+## 技术要点
+
+### 1. 事务管理架构
+- **Service层或Handler层负责事务管理**:在上层开启和管理事务
+- **Logic层只检查事务状态**:使用 `\UCore\Db\Helper::check_tr()` 确保在事务中执行
+- **避免事务嵌套**:防止 "transaction level > 1" 错误
+
+### 2. 异常处理原则
+- **不隐藏异常**:所有异常必须重新抛出
+- **保持原子性**:确保逻辑要么全部成功,要么全部失败
+- **记录日志后抛出**:可以记录错误日志,但必须重新抛出异常
+
+### 3. 特殊业务场景
+- **批量处理**:某些业务场景需要独立事务处理,需要明确注释说明
+- **业务需求优先**:在特殊情况下,业务需求可以覆盖一般规范
+
+## 影响范围
+
+### 1. 修复的文件
+- `app/Module/UrsPromotion/Logics/UrsProfitLogic.php`
+- `app/Module/UrsPromotion/Logics/UrsPartnerDividendLogic.php`
+- `app/Module/Farm/Logics/FarmLogic.php`
+- `app/Module/Farm/Logics/CropLogic.php`
+- `app/Module/Farm/Logics/DisasterLogic.php`
+
+### 2. 代码统计
+- **修改文件数**:5个
+- **主要修改**:异常处理规范化、事务管理规范化
+- **特殊处理**:1个(UrsPartnerDividendLogic的批量分红场景)
+
+## 总结
+
+通过系统性的检查和修复,项目中的Logic层现在更严格地遵循架构规范:
+
+1. **事务管理规范化**:Logic层不再开启事务(除特殊业务场景),只进行事务状态检查
+2. **异常处理规范化**:所有异常都正确重新抛出,不会被隐藏
+3. **代码架构清晰**:明确了各层的职责分工
+4. **提高系统稳定性**:避免了事务嵌套和异常隐藏导致的问题
+
+这次修复确保了代码的原子性和一致性,提高了系统的可维护性和稳定性。同时保留了特殊业务场景的灵活性。

+ 1 - 1
AiWork/WORK.md

@@ -6,4 +6,4 @@
 
 - 逻辑层不能开启事务,需要事务进行事务开启检查,不能进行异常Try/Catch,这会导致异常被隐藏
 - 保持逻辑的原子性,不能让逻辑部分成功(异常被Catch导致外层无法收到错误而继续执行)
-检查,注意修改是,检查引用
+检查,修改后,检查调用这些方法的地方

+ 3 - 3
app/Module/Article/Logics/ArticleLogic.php

@@ -60,7 +60,7 @@ class ArticleLogic
                 'id' => $id,
                 'data' => $data
             ]);
-            return false;
+            throw $e; // 重新抛出异常
         }
     }
 
@@ -88,7 +88,7 @@ class ArticleLogic
                 'error' => $e->getMessage(),
                 'id' => $id
             ]);
-            return false;
+            throw $e; // 重新抛出异常
         }
     }
 
@@ -114,7 +114,7 @@ class ArticleLogic
                 'error' => $e->getMessage(),
                 'id' => $id
             ]);
-            return false;
+            throw $e; // 重新抛出异常
         }
     }
 

+ 1 - 1
app/Module/Farm/Logics/CropLogic.php

@@ -55,7 +55,7 @@ class CropLogic
                 'trace'   => $e->getTraceAsString()
             ]);
 
-            return null;
+            throw $e; // 重新抛出异常
         }
     }
 

+ 1 - 1
app/Module/Farm/Logics/DisasterLogic.php

@@ -47,7 +47,7 @@ class DisasterLogic
                 'trace'   => $e->getTraceAsString()
             ]);
 
-            return collect();
+            throw $e; // 重新抛出异常
         }
     }
 

+ 3 - 2
app/Module/Farm/Logics/FarmLogic.php

@@ -35,7 +35,7 @@ class FarmLogic
                 'trace' => $e->getTraceAsString()
             ]);
 
-            return null;
+            throw $e; // 重新抛出异常
         }
     }
 
@@ -84,7 +84,7 @@ class FarmLogic
                 'trace' => $e->getTraceAsString()
             ]);
 
-            return null;
+            throw $e; // 重新抛出异常
         }
     }
 
@@ -138,6 +138,7 @@ class FarmLogic
                 'error' => $e->getMessage(),
                 'trace' => $e->getTraceAsString()
             ]);
+            throw $e; // 重新抛出异常
         }
     }
 }

+ 2 - 4
app/Module/Task/Logics/TaskLogic.php

@@ -92,7 +92,7 @@ class TaskLogic
                 'trace' => $e->getTraceAsString()
             ]);
 
-            return \UCore\Dto\Res::error($e->getMessage());
+            throw $e; // 重新抛出异常
         }
     }
 
@@ -126,9 +126,7 @@ class TaskLogic
                 'trace' => $e->getTraceAsString()
             ]);
 
-            return \UCore\Dto\Res::error($e->getMessage(), [
-                'rewards' => []
-            ]);
+            throw $e; // 重新抛出异常
         }
     }
 

+ 2 - 1
app/Module/UrsPromotion/Logics/UrsPartnerDividendLogic.php

@@ -309,7 +309,8 @@ class UrsPartnerDividendLogic
 
         foreach ($batch as $detail) {
             try {
-                // 使用独立事务处理每个转账
+                // 特殊情况:批量分红需要独立事务处理每个转账,确保单个失败不影响其他转账
+                // 这是业务需求,与一般Logic层规范不同
                 DB::transaction(function () use ($detail, $dividendRecord, $perPartnerAmount, &$successCount, &$failedCount) {
                     // 执行手续费转移
                     $transferResult = FeeService::transfer(

+ 6 - 9
app/Module/UrsPromotion/Logics/UrsProfitLogic.php

@@ -13,7 +13,7 @@ use App\Module\UrsPromotion\Enums\UrsProfitType;
 use App\Module\UrsPromotion\Enums\UrsPromotionRelationLevel;
 use App\Module\Game\Services\RewardService;
 use App\Module\GameItems\Services\ItemService;
-use Illuminate\Support\Facades\DB;
+
 use Illuminate\Support\Facades\Log;
 
 /**
@@ -79,6 +79,7 @@ class UrsProfitLogic
                 'source_id' => $sourceId,
                 'error' => $e->getMessage()
             ]);
+            throw $e; // 重新抛出异常
         }
 
         return $profits;
@@ -297,8 +298,8 @@ class UrsProfitLogic
             return null;
         }
 
-        // 开启事务(奖励组系统要求在事务中执行)
-        DB::beginTransaction();
+        // 检查事务状态,确保调用者已开启事务
+        \UCore\Db\Helper::check_tr();
 
         try {
             // 使用奖励组系统发放奖励
@@ -310,13 +311,12 @@ class UrsProfitLogic
             );
 
             if (!$rewardResult->success) {
-                DB::rollBack();
                 Log::error("推广奖励发放失败", [
                     'referrer_id' => $referrerId,
                     'reward_group_id' => $rewardGroupId,
                     'error' => $rewardResult->errorMessage
                 ]);
-                return null;
+                throw new \Exception("推广奖励发放失败: " . $rewardResult->errorMessage);
             }
 
             // 计算奖励总金额(用于记录)
@@ -348,16 +348,13 @@ class UrsProfitLogic
                 'status' => UrsProfit::STATUS_NORMAL,
             ]);
 
-            DB::commit();
-
         } catch (\Exception $e) {
-            DB::rollBack();
             Log::error("推广奖励发放事务失败", [
                 'referrer_id' => $referrerId,
                 'reward_group_id' => $rewardGroupId,
                 'error' => $e->getMessage()
             ]);
-            return null;
+            throw $e; // 重新抛出异常
         }
 
         Log::info("URS推广收益记录创建", [