30日2015-修复作物final_output_item_id确定逻辑bug.md 8.1 KB

修复作物final_output_item_id确定逻辑bug

任务描述

修复UpdateCropGrowthCommand没有正确处理final_output_item_id的bug,确保作物在发芽期必须确定最终产出果实ID

问题分析

背景

根据系统设计,作物应该在进入发芽期(SPROUT阶段)时确定final_output_item_id,这是系统的核心逻辑。但是发现有成熟期的作物没有确定果实final_output_item_id,这是一个严重的bug。

问题根源

1. UpdateCropGrowthCommand的问题

UpdateCropGrowthCommand是定时任务中更新作物生长状态的核心命令,但它有以下问题:

// 原有的错误实现
foreach ($crops as $crop) {
    $userId = $crop->user_id;
    $oldStage = $crop->growth_stage;

    // 直接计算新的生长阶段
    $newStage = $this->calculateNextStage($crop);
    
    // 直接更新作物信息,没有调用CropLogic的完整逻辑
    $crop->growth_stage = $newStage;
    $crop->stage_start_time = now();
    $crop->stage_end_time = $stageEndTime;
    $crop->fertilized = false;
    $crop->save(); // 没有处理final_output_item_id
}

问题

  • 没有调用CropLogic中的updateGrowthStage方法
  • 直接更新作物状态,跳过了final_output_item_id的设置逻辑
  • 导致作物进入发芽期时没有确定最终产出果实ID

2. 逻辑不一致

  • CropLogic::updateGrowthStage():包含完整的生长阶段更新逻辑,包括final_output_item_id的设置
  • UpdateCropGrowthCommand:只更新基本字段,缺少关键逻辑

影响范围

  • 通过定时任务更新的作物可能没有final_output_item_id
  • 成熟期作物无法正确显示果实信息
  • 收获时需要使用兼容逻辑,影响系统一致性

解决方案

1. 修复UpdateCropGrowthCommand

1.1 使用CropLogic的完整逻辑

// 修复后的实现
foreach ($crops as $crop) {
    $userId = $crop->user_id;
    $oldStage = $crop->growth_stage;

    // 使用CropLogic的updateGrowthStage方法,确保所有逻辑都正确执行
    $cropLogic = new CropLogic();
    $updated = $cropLogic->updateGrowthStage($crop->id);

    if ($updated) {
        $updatedCount++;
        // 重新获取作物信息以显示更新后的状态
        $crop->refresh();
        $this->info("作物 ID: {$crop->id}, 用户 ID: {$userId}, 阶段: {$oldStage} -> {$crop->growth_stage}");
    }
}

1.2 清理冗余代码

  • 删除重复的calculateNextStagecalculateStageEndTime方法
  • 移除不再使用的导入

2. 强化CropLogic中的验证

2.1 发芽期逻辑强化

// 如果进入发芽期,必须确定最终产出果实ID
if ($newStage === GROWTH_STAGE::SPROUT->value) {
    if (!$crop->final_output_item_id) {
        $outputInfo = $this->getRandomOutput($crop->seed_id);
        $crop->final_output_item_id = $outputInfo['item_id'];

        Log::info('作物进入发芽期,确定最终产出果实', [
            'crop_id' => $crop->id,
            'user_id' => $crop->user_id,
            'seed_id' => $crop->seed_id,
            'final_output_item_id' => $crop->final_output_item_id
        ]);
    }
}

2.2 成熟期严格验证

// 验证:如果进入成熟期但没有final_output_item_id,这是一个严重错误
if ($newStage === GROWTH_STAGE::MATURE->value && !$crop->final_output_item_id) {
    Log::error('严重错误:作物进入成熟期但没有确定最终产出果实ID', [
        'crop_id' => $crop->id,
        'user_id' => $crop->user_id,
        'seed_id' => $crop->seed_id,
        'current_stage' => $oldStage,
        'new_stage' => $newStage
    ]);
    
    throw new \Exception("作物ID {$crop->id} 进入成熟期但没有确定最终产出果实ID,这是系统错误");
}

3. 创建修复命令

3.1 FixCropFinalOutputCommand

创建专门的修复命令来处理现有的有问题的作物数据:

php artisan farm:fix-crop-final-output --dry-run  // 查看需要修复的数据
php artisan farm:fix-crop-final-output            // 实际修复

3.2 修复逻辑

  • 查找所有发芽期及以后但没有final_output_item_id的作物
  • 为这些作物确定最终产出果实ID
  • 记录修复过程和结果

4. 方法可见性调整

CropLogic::getRandomOutput()方法从private改为public,供修复命令使用。

修改内容

修改的文件

1. app/Module/Farm/Commands/UpdateCropGrowthCommand.php

  • 主要修改:使用CropLogic的updateGrowthStage方法替代直接更新
  • 删除内容:重复的calculateNextStage和calculateStageEndTime方法
  • 清理导入:移除不再使用的CropGrowthStageChangedEvent导入

2. app/Module/Farm/Logics/CropLogic.php

  • 强化验证:移除兼容处理,增加严格的错误检查
  • 方法可见性:将getRandomOutput方法改为public
  • 错误处理:成熟期没有final_output_item_id时抛出异常

3. app/Module/Farm/Commands/FixCropFinalOutputCommand.php(新增)

  • 修复命令:专门用于修复现有问题数据
  • 干运行模式:支持--dry-run参数查看需要修复的数据
  • 详细日志:记录修复过程和结果

技术要点

1. 系统一致性

  • 确保所有作物生长阶段更新都通过统一的逻辑
  • 消除代码重复,避免逻辑不一致
  • 强化核心业务规则的执行

2. 错误处理策略

  • 不兼容处理:这是bug,不应该用兼容逻辑掩盖
  • 严格验证:成熟期没有final_output_item_id时直接抛出异常
  • 早期发现:在发芽期就确保final_output_item_id被设置

3. 数据修复

  • 安全修复:提供干运行模式查看影响范围
  • 详细记录:记录所有修复操作
  • 用户确认:修复前需要用户确认

4. 日志记录

  • 信息日志:正常的final_output_item_id设置
  • 错误日志:严重的系统错误
  • 修复日志:数据修复过程

业务价值

1. 数据一致性

  • 确保所有作物都有正确的final_output_item_id
  • 保证果实信息显示的准确性
  • 维护系统数据的完整性

2. 系统稳定性

  • 消除随机的兼容逻辑
  • 减少收获时的不确定性
  • 提高系统的可预测性

3. 用户体验

  • 果实信息显示更加准确
  • 用户可以在发芽期就看到最终产出
  • 减少用户困惑和投诉

4. 开发维护

  • 代码逻辑更加清晰
  • 减少bug的产生
  • 便于后续功能开发

验证方法

1. 运行修复命令

# 查看需要修复的数据
php artisan farm:fix-crop-final-output --dry-run

# 执行修复
php artisan farm:fix-crop-final-output

2. 检查日志

  • 查看是否有"严重错误"日志
  • 确认所有发芽期作物都有final_output_item_id
  • 验证修复命令的执行结果

3. 功能测试

  • 种植新作物,确认发芽期时设置final_output_item_id
  • 检查农场用户信息汇总页面的果实信息显示
  • 验证收获功能的正常运行

风险评估

1. 低风险

  • 修复逻辑基于现有的getRandomOutput方法
  • 不改变核心业务逻辑,只是确保逻辑的正确执行
  • 提供干运行模式,可以预先查看影响

2. 注意事项

  • 修复命令会修改现有数据,需要谨慎操作
  • 严格验证可能会暴露更多的数据问题
  • 需要监控日志,及时发现新的问题

后续计划

1. 监控

  • 持续监控作物生长阶段更新的日志
  • 关注是否还有final_output_item_id缺失的情况
  • 定期检查数据一致性

2. 优化

  • 考虑在种植时就预设final_output_item_id
  • 优化产出概率算法
  • 增加更多的数据验证机制

3. 文档更新

  • 更新种子与作物系统文档
  • 完善错误处理指南
  • 记录数据修复流程

任务状态

✅ 已完成

相关文件

  • app/Module/Farm/Commands/UpdateCropGrowthCommand.php - 修复主要bug
  • app/Module/Farm/Logics/CropLogic.php - 强化验证逻辑
  • app/Module/Farm/Commands/FixCropFinalOutputCommand.php - 新增修复命令

影响范围

  • 修复了定时任务中作物生长状态更新的核心bug
  • 确保了所有作物在发芽期都会正确设置final_output_item_id
  • 提供了修复现有问题数据的工具
  • 强化了系统的数据一致性和稳定性