UrsRebuildRelationCacheCommand.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. <?php
  2. namespace App\Module\UrsPromotion\Commands;
  3. use App\Module\UrsPromotion\Logics\UrsRelationCacheLogic;
  4. use Illuminate\Console\Command;
  5. /**
  6. * URS用户关系缓存重建命令
  7. *
  8. * 用于批量重建URS用户关系缓存,提升查询性能
  9. *
  10. * 使用示例:
  11. * php artisan urs:rebuild-relation-cache # 重建所有用户缓存
  12. * php artisan urs:rebuild-relation-cache --check # 检查缓存完整性
  13. * php artisan urs:rebuild-relation-cache --fix # 修复发现的问题
  14. * php artisan urs:rebuild-relation-cache --user=123 # 重建指定用户缓存
  15. * php artisan urs:rebuild-relation-cache --users=123,456 # 重建多个用户缓存
  16. * php artisan urs:rebuild-relation-cache --user=123 --clear # 清除指定用户缓存
  17. */
  18. class UrsRebuildRelationCacheCommand extends Command
  19. {
  20. /**
  21. * 命令签名
  22. */
  23. protected $signature = 'urs:rebuild-relation-cache
  24. {--batch-size=100 : 批处理大小}
  25. {--check : 仅检查完整性,不重建}
  26. {--fix : 修复发现的问题}
  27. {--user= : 指定URS用户ID,仅处理该用户}
  28. {--users= : 指定多个URS用户ID,用逗号分隔}
  29. {--clear : 清除指定用户的缓存(需配合--user或--users使用)}';
  30. /**
  31. * 命令描述
  32. */
  33. protected $description = 'URS用户关系缓存重建命令,支持全量重建、指定用户处理、完整性检查和问题修复';
  34. /**
  35. * 执行命令
  36. */
  37. public function handle()
  38. {
  39. $logic = new UrsRelationCacheLogic();
  40. // 处理指定用户的缓存操作
  41. if ($this->option('user') || $this->option('users')) {
  42. return $this->handleSpecificUsers($logic);
  43. }
  44. // 仅检查完整性
  45. if ($this->option('check')) {
  46. $this->info('开始检查URS关系缓存完整性...');
  47. $result = $logic->checkRelationCacheIntegrity();
  48. if (isset($result['error'])) {
  49. $this->error('检查失败: ' . $result['error']);
  50. return 1;
  51. }
  52. $this->info('检查结果:');
  53. $this->table(['项目', '数量'], [
  54. ['总用户数', $result['total_users']],
  55. ['有缓存的用户数', $result['users_with_cache']],
  56. ['缺失缓存的用户数', $result['missing_users']],
  57. ['循环推荐关系数', $result['circular_relations']],
  58. ['孤立缓存数', $result['orphaned_caches']]
  59. ]);
  60. if ($result['missing_users'] > 0 || $result['orphaned_caches'] > 0) {
  61. $this->warn('发现问题,建议使用 --fix 参数修复');
  62. return 1;
  63. }
  64. $this->info('缓存完整性检查通过');
  65. return 0;
  66. }
  67. // 修复问题
  68. if ($this->option('fix')) {
  69. $this->info('开始修复URS关系缓存问题...');
  70. // 先检查需要修复的数量
  71. $integrity = $logic->checkRelationCacheIntegrity();
  72. $totalToFix = $integrity['missing_users'] + $integrity['orphaned_caches'];
  73. if ($totalToFix == 0) {
  74. $this->info('没有发现需要修复的问题');
  75. return 0;
  76. }
  77. $progressBar = $this->output->createProgressBar($totalToFix);
  78. $progressBar->setFormat(' %current%/%max% [%bar%] %percent:3s%% - %message%');
  79. $progressBar->setMessage('准备修复...');
  80. $progressBar->start();
  81. $currentProgress = 0;
  82. // 定义进度回调函数
  83. $progressCallback = function($type, $ursUserId, $processed, $total, $fixed) use ($progressBar, &$currentProgress) {
  84. $currentProgress++;
  85. $typeText = $type === 'missing' ? '修复缺失缓存' : '清理孤立缓存';
  86. $progressBar->setMessage("{$typeText} - URS用户ID: {$ursUserId} (已修复: {$fixed})");
  87. $progressBar->setProgress($currentProgress);
  88. };
  89. $result = $logic->fixRelationCacheIssues($progressCallback);
  90. $progressBar->finish();
  91. $this->newLine();
  92. if (isset($result['error'])) {
  93. $this->error('修复失败: ' . $result['error']);
  94. return 1;
  95. }
  96. $this->info('修复结果:');
  97. $this->table(['项目', '修复数量'], [
  98. ['缺失用户缓存', $result['fixed']['missing_users']],
  99. ['孤立缓存清理', $result['fixed']['orphaned_caches']]
  100. ]);
  101. $this->info('问题修复完成');
  102. return 0;
  103. }
  104. // 重建所有缓存
  105. $batchSize = (int) $this->option('batch-size');
  106. if (!$this->confirm('确定要重建所有URS用户关系缓存吗?这将清空现有缓存并重新生成。')) {
  107. $this->info('操作已取消');
  108. return 0;
  109. }
  110. $this->info("开始重建URS关系缓存,批处理大小: {$batchSize}");
  111. // 先获取总用户数用于进度条初始化
  112. $totalUsers = \App\Module\UrsPromotion\Models\UrsUserReferral::where('status', \App\Module\UrsPromotion\Models\UrsUserReferral::STATUS_VALID)->count();
  113. $progressBar = $this->output->createProgressBar($totalUsers);
  114. $progressBar->setFormat(' %current%/%max% [%bar%] %percent:3s%% - 当前用户ID: %message%');
  115. $progressBar->setMessage('准备开始...');
  116. $progressBar->start();
  117. // 定义进度回调函数
  118. $progressCallback = function($ursUserId, $processedCount, $totalUsers, $successCount, $failCount) use ($progressBar) {
  119. $progressBar->setMessage("URS用户ID: {$ursUserId} (成功: {$successCount}, 失败: {$failCount})");
  120. $progressBar->setProgress($processedCount);
  121. };
  122. $result = $logic->rebuildAllRelationCache($batchSize, $progressCallback);
  123. $progressBar->finish();
  124. $this->newLine();
  125. if (isset($result['error'])) {
  126. $this->error('重建失败: ' . $result['error']);
  127. return 1;
  128. }
  129. $this->info('重建完成:');
  130. $this->table(['项目', '数量'], [
  131. ['总用户数', $result['total']],
  132. ['成功数', $result['success']],
  133. ['失败数', $result['fail']]
  134. ]);
  135. if ($result['fail'] > 0) {
  136. $this->warn('部分用户缓存生成失败,请检查日志');
  137. return 1;
  138. }
  139. $this->info('所有URS用户关系缓存重建完成');
  140. return 0;
  141. }
  142. /**
  143. * 处理指定用户的缓存操作
  144. *
  145. * @param UrsRelationCacheLogic $logic
  146. * @return int
  147. */
  148. private function handleSpecificUsers(UrsRelationCacheLogic $logic): int
  149. {
  150. // 获取用户ID列表
  151. $userIds = $this->getSpecifiedUserIds();
  152. if (empty($userIds)) {
  153. $this->error('未指定有效的用户ID');
  154. return 1;
  155. }
  156. $this->info('指定处理的URS用户ID: ' . implode(', ', $userIds));
  157. // 验证用户ID是否存在
  158. $validUserIds = $this->validateUserIds($userIds);
  159. if (empty($validUserIds)) {
  160. $this->error('所有指定的用户ID都无效');
  161. return 1;
  162. }
  163. if (count($validUserIds) < count($userIds)) {
  164. $invalidIds = array_diff($userIds, $validUserIds);
  165. $this->warn('以下用户ID无效,将被跳过: ' . implode(', ', $invalidIds));
  166. }
  167. // 清除缓存操作
  168. if ($this->option('clear')) {
  169. return $this->clearSpecificUsersCache($logic, $validUserIds);
  170. }
  171. // 重建指定用户的缓存
  172. return $this->rebuildSpecificUsersCache($logic, $validUserIds);
  173. }
  174. /**
  175. * 获取指定的用户ID列表
  176. *
  177. * @return array
  178. */
  179. private function getSpecifiedUserIds(): array
  180. {
  181. $userIds = [];
  182. // 处理单个用户ID
  183. if ($this->option('user')) {
  184. $userId = (int) $this->option('user');
  185. if ($userId > 0) {
  186. $userIds[] = $userId;
  187. }
  188. }
  189. // 处理多个用户ID
  190. if ($this->option('users')) {
  191. $usersString = $this->option('users');
  192. $userIdStrings = explode(',', $usersString);
  193. foreach ($userIdStrings as $userIdString) {
  194. $userId = (int) trim($userIdString);
  195. if ($userId > 0 && !in_array($userId, $userIds)) {
  196. $userIds[] = $userId;
  197. }
  198. }
  199. }
  200. return $userIds;
  201. }
  202. /**
  203. * 验证用户ID是否存在于URS推荐关系中
  204. *
  205. * @param array $userIds
  206. * @return array
  207. */
  208. private function validateUserIds(array $userIds): array
  209. {
  210. return \App\Module\UrsPromotion\Models\UrsUserReferral::whereIn('urs_user_id', $userIds)
  211. ->where('status', \App\Module\UrsPromotion\Models\UrsUserReferral::STATUS_VALID)
  212. ->pluck('urs_user_id')
  213. ->toArray();
  214. }
  215. /**
  216. * 清除指定用户的缓存
  217. *
  218. * @param UrsRelationCacheLogic $logic
  219. * @param array $userIds
  220. * @return int
  221. */
  222. private function clearSpecificUsersCache(UrsRelationCacheLogic $logic, array $userIds): int
  223. {
  224. $this->info('开始清除指定用户的关系缓存...');
  225. $progressBar = $this->output->createProgressBar(count($userIds));
  226. $progressBar->setFormat(' %current%/%max% [%bar%] %percent:3s%% - 当前用户ID: %message%');
  227. $progressBar->start();
  228. $successCount = 0;
  229. $failCount = 0;
  230. foreach ($userIds as $userId) {
  231. $progressBar->setMessage("URS用户ID: {$userId}");
  232. if ($logic->clearUserRelationCache($userId)) {
  233. $successCount++;
  234. } else {
  235. $failCount++;
  236. }
  237. $progressBar->advance();
  238. }
  239. $progressBar->finish();
  240. $this->newLine();
  241. $this->info('缓存清除完成:');
  242. $this->table(['项目', '数量'], [
  243. ['处理用户数', count($userIds)],
  244. ['成功数', $successCount],
  245. ['失败数', $failCount]
  246. ]);
  247. if ($failCount > 0) {
  248. $this->warn('部分用户缓存清除失败,请检查日志');
  249. return 1;
  250. }
  251. $this->info('指定用户关系缓存清除完成');
  252. return 0;
  253. }
  254. /**
  255. * 重建指定用户的缓存
  256. *
  257. * @param UrsRelationCacheLogic $logic
  258. * @param array $userIds
  259. * @return int
  260. */
  261. private function rebuildSpecificUsersCache(UrsRelationCacheLogic $logic, array $userIds): int
  262. {
  263. $this->info('开始重建指定用户的关系缓存...');
  264. $progressBar = $this->output->createProgressBar(count($userIds));
  265. $progressBar->setFormat(' %current%/%max% [%bar%] %percent:3s%% - 当前用户ID: %message%');
  266. $progressBar->start();
  267. $successCount = 0;
  268. $failCount = 0;
  269. foreach ($userIds as $userId) {
  270. $progressBar->setMessage("URS用户ID: {$userId}");
  271. if ($logic->generateUserRelationCache($userId)) {
  272. $successCount++;
  273. } else {
  274. $failCount++;
  275. }
  276. $progressBar->advance();
  277. }
  278. $progressBar->finish();
  279. $this->newLine();
  280. $this->info('缓存重建完成:');
  281. $this->table(['项目', '数量'], [
  282. ['处理用户数', count($userIds)],
  283. ['成功数', $successCount],
  284. ['失败数', $failCount]
  285. ]);
  286. if ($failCount > 0) {
  287. $this->warn('部分用户缓存生成失败,请检查日志');
  288. return 1;
  289. }
  290. $this->info('指定用户关系缓存重建完成');
  291. return 0;
  292. }
  293. }