CollectUserLogsContinuousCommand.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <?php
  2. namespace App\Module\Game\Commands;
  3. use App\Module\Game\Logics\UserLogCollectorManager;
  4. use UCore\Command\Command;
  5. /**
  6. * 用户日志持续收集命令
  7. *
  8. * 持续运行的日志收集命令,循环100次后退出,间隔1秒
  9. * 复用CollectUserLogsCommand的核心逻辑
  10. */
  11. class CollectUserLogsContinuousCommand extends Command
  12. {
  13. /**
  14. * 命令名称和参数
  15. *
  16. * @var string
  17. */
  18. protected $signature = 'game:collect-user-logs-continuous {--detail : 显示详细的处理过程} {--limit=100 : 单次处理最大记录数} {--cycles=100 : 循环次数} {--interval=1 : 间隔秒数}';
  19. /**
  20. * 命令描述
  21. *
  22. * @var string
  23. */
  24. protected $description = '持续收集用户日志,循环指定次数后退出
  25. 选项说明:
  26. --detail 显示详细的处理过程
  27. --limit 单次处理最大记录数(默认100)
  28. --cycles 循环次数(默认100)
  29. --interval 间隔秒数(默认1秒)
  30. 进度追踪机制:
  31. - 基于原始日志ID进行进度追踪,确保不遗漏任何记录
  32. - 每个收集器独立追踪进度,无需手动重置
  33. - 适用于需要持续监控日志收集的场景';
  34. /**
  35. * 执行命令
  36. */
  37. public function handleRun()
  38. {
  39. $detail = $this->option('detail');
  40. $limit = (int)$this->option('limit');
  41. $cycles = (int)$this->option('cycles');
  42. $interval = (int)$this->option('interval');
  43. // 参数验证
  44. if ($cycles <= 0) {
  45. $this->error("❌ 循环次数必须大于0");
  46. return 1;
  47. }
  48. if ($interval <= 0) {
  49. $this->error("❌ 间隔时间不能 <= 0");
  50. return 1;
  51. }
  52. $this->info("🚀 开始持续收集用户日志...");
  53. $this->line("📊 配置信息:");
  54. $this->line(" 🔄 循环次数: <info>{$cycles}</info>");
  55. $this->line(" ⏱️ 间隔时间: <info>{$interval}秒</info>");
  56. $this->line(" 📝 单次限制: <info>{$limit}条</info>");
  57. $this->line("");
  58. $manager = new UserLogCollectorManager();
  59. $totalProcessed = 0;
  60. $totalExecutionTime = 0;
  61. $successfulCycles = 0;
  62. $failedCycles = 0;
  63. $startTime = microtime(true);
  64. for ($i = 1; $i <= $cycles; $i++) {
  65. $this->line("循环 {$i} ");
  66. $cycleStartTime = microtime(true);
  67. try {
  68. if ($detail) {
  69. $this->line("🔄 第 {$i}/{$cycles} 次循环开始...");
  70. }
  71. // 复用原有的收集逻辑
  72. $result = $this->executeTimelineCollection($manager, $limit, $detail);
  73. $cycleEndTime = microtime(true);
  74. $cycleExecutionTime = round(($cycleEndTime - $cycleStartTime) * 1000, 2);
  75. $totalProcessed += $result['processed_count'];
  76. $totalExecutionTime += $cycleExecutionTime;
  77. $successfulCycles++;
  78. if ($detail) {
  79. $this->line("✅ 第 {$i} 次循环完成: 处理 {$result['processed_count']} 条记录,耗时 {$cycleExecutionTime}ms");
  80. } else {
  81. // 简化输出,只显示有处理记录的循环
  82. if ($result['processed_count'] > 0) {
  83. $this->line("✅ 第 {$i} 次: 处理 {$result['processed_count']} 条记录");
  84. }
  85. }
  86. } catch (\Exception $e) {
  87. $failedCycles++;
  88. $this->error("❌ 第 {$i} 次循环失败: {$e->getMessage()}");
  89. if ($detail) {
  90. $this->line("🚨 错误详情: " . $e->getTraceAsString());
  91. }
  92. }
  93. // 如果不是最后一次循环,则等待间隔时间
  94. if ($i < $cycles && $interval > 0) {
  95. if ($detail) {
  96. $this->line("⏳ 等待 {$interval} 秒...");
  97. }
  98. sleep($interval);
  99. }
  100. }
  101. $endTime = microtime(true);
  102. $totalRealTime = round(($endTime - $startTime) * 1000, 2);
  103. // 显示最终统计
  104. $this->displayFinalStatistics($cycles, $successfulCycles, $failedCycles, $totalProcessed, $totalExecutionTime, $totalRealTime);
  105. return $failedCycles > 0 ? 1 : 0;
  106. }
  107. /**
  108. * 执行时间线收集(复用原有逻辑)
  109. *
  110. * @param UserLogCollectorManager $manager
  111. * @param int $limit
  112. * @param bool $detail
  113. * @return array
  114. */
  115. private function executeTimelineCollection(UserLogCollectorManager $manager, int $limit, bool $detail): array
  116. {
  117. $startTime = microtime(true);
  118. // 直接执行所有收集器,传递限制参数
  119. $results = $manager->collectAll($limit);
  120. if ($results['total_processed'] == 0) {
  121. return [
  122. 'processed_count' => 0,
  123. 'execution_time' => round((microtime(true) - $startTime) * 1000, 2),
  124. 'status' => 'success',
  125. 'message' => '没有新记录需要处理',
  126. 'timestamp' => now()->toDateTimeString()
  127. ];
  128. }
  129. if ($detail) {
  130. foreach ($results['collectors'] as $collectorName => $result) {
  131. if ($result['processed_count'] > 0) {
  132. $this->line(" {$collectorName}: 处理了 {$result['processed_count']} 条记录");
  133. }
  134. }
  135. }
  136. $endTime = microtime(true);
  137. return [
  138. 'processed_count' => $results['total_processed'],
  139. 'execution_time' => round(($endTime - $startTime) * 1000, 2),
  140. 'status' => 'success',
  141. 'timestamp' => now()->toDateTimeString(),
  142. 'details' => $results['collectors']
  143. ];
  144. }
  145. /**
  146. * 显示最终统计信息
  147. *
  148. * @param int $totalCycles
  149. * @param int $successfulCycles
  150. * @param int $failedCycles
  151. * @param int $totalProcessed
  152. * @param float $totalExecutionTime
  153. * @param float $totalRealTime
  154. * @return void
  155. */
  156. private function displayFinalStatistics(int $totalCycles, int $successfulCycles, int $failedCycles, int $totalProcessed, float $totalExecutionTime, float $totalRealTime): void
  157. {
  158. $this->line("");
  159. $this->info("🎉 持续收集完成!");
  160. $this->line("");
  161. $this->line("📊 <comment>执行统计</comment>:");
  162. $this->line(" 🔄 总循环次数: <info>{$totalCycles}</info>");
  163. $this->line(" ✅ 成功次数: <info>{$successfulCycles}</info>");
  164. if ($failedCycles > 0) {
  165. $this->line(" ❌ 失败次数: <error>{$failedCycles}</error>");
  166. }
  167. $this->line(" 📝 总处理记录: <info>{$totalProcessed}</info>");
  168. $this->line(" ⏱️ 总执行时间: <info>{$totalExecutionTime}ms</info>");
  169. $this->line(" 🕐 总运行时间: <info>{$totalRealTime}ms</info>");
  170. if ($totalProcessed > 0) {
  171. $avgTimePerRecord = round($totalExecutionTime / $totalProcessed, 2);
  172. $this->line(" 📈 平均处理时间: <info>{$avgTimePerRecord}ms/条</info>");
  173. }
  174. if ($successfulCycles > 0) {
  175. $avgRecordsPerCycle = round($totalProcessed / $successfulCycles, 2);
  176. $this->line(" 📊 平均每次处理: <info>{$avgRecordsPerCycle}条</info>");
  177. }
  178. $successRate = round(($successfulCycles / $totalCycles) * 100, 2);
  179. $this->line(" 🎯 成功率: <info>{$successRate}%</info>");
  180. $this->line("");
  181. }
  182. }