CleanupService.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. <?php
  2. namespace App\Module\Cleanup\Services;
  3. use App\Module\Cleanup\Logics\ModelScannerLogic;
  4. use App\Module\Cleanup\Logics\CleanupPlanLogic;
  5. use App\Module\Cleanup\Logics\CleanupTaskLogic;
  6. use App\Module\Cleanup\Logics\CleanupExecutorLogic;
  7. use App\Module\Cleanup\Logics\BackupLogic;
  8. use App\Module\Cleanup\Models\CleanupPlan;
  9. use App\Module\Cleanup\Models\CleanupTask;
  10. use App\Module\Cleanup\Models\CleanupBackup;
  11. use App\Module\Cleanup\Models\CleanupSqlBackup;
  12. /**
  13. * 清理服务类
  14. *
  15. * 提供对外的清理服务接口
  16. */
  17. class CleanupService
  18. {
  19. /**
  20. * 扫描Model类(推荐使用)
  21. *
  22. * @param bool $forceRefresh 是否强制刷新
  23. * @return array 扫描结果
  24. */
  25. public static function scanModels(bool $forceRefresh = false): array
  26. {
  27. return ModelScannerLogic::scanAllModels($forceRefresh);
  28. }
  29. /**
  30. * 扫描系统中的所有数据表(已废弃,建议使用scanModels)
  31. *
  32. * @deprecated 请使用 scanModels() 方法
  33. * @param bool $forceRefresh 是否强制刷新
  34. * @return array 扫描结果
  35. */
  36. public static function scanTables(bool $forceRefresh = false): array
  37. {
  38. // 为了向后兼容,重定向到新的Model扫描方法
  39. return static::scanModels($forceRefresh);
  40. }
  41. /**
  42. * 创建清理计划
  43. *
  44. * @param array $planData 计划数据
  45. * @return array 创建结果
  46. */
  47. public static function createCleanupPlan(array $planData): array
  48. {
  49. return CleanupPlanLogic::createPlan($planData);
  50. }
  51. /**
  52. * 为计划生成内容配置
  53. *
  54. * @param int $planId 计划ID
  55. * @param bool $autoGenerate 是否自动生成
  56. * @return array 生成结果
  57. */
  58. public static function generatePlanContents(int $planId, bool $autoGenerate = true): array
  59. {
  60. return CleanupPlanLogic::generateContents($planId, $autoGenerate);
  61. }
  62. /**
  63. * 基于计划创建清理任务
  64. *
  65. * @param int $planId 计划ID
  66. * @param array $taskOptions 任务选项
  67. * @return array 创建结果
  68. */
  69. public static function createCleanupTask(int $planId, array $taskOptions = []): array
  70. {
  71. return CleanupTaskLogic::createTask($planId, $taskOptions);
  72. }
  73. /**
  74. * 预览计划的清理结果
  75. *
  76. * @param int $planId 计划ID
  77. * @return array 预览结果
  78. */
  79. public static function previewPlanCleanup(int $planId): array
  80. {
  81. return CleanupExecutorLogic::previewPlanCleanup($planId);
  82. }
  83. /**
  84. * 预览任务的清理结果
  85. *
  86. * @param int $taskId 任务ID
  87. * @return array 预览结果
  88. */
  89. public static function previewTaskCleanup(int $taskId): array
  90. {
  91. return CleanupExecutorLogic::previewTaskCleanup($taskId);
  92. }
  93. /**
  94. * 执行清理任务
  95. *
  96. * @param int $taskId 任务ID
  97. * @param bool $dryRun 是否为预演模式
  98. * @return array 执行结果
  99. */
  100. public static function executeCleanupTask(int $taskId, bool $dryRun = false): array
  101. {
  102. return CleanupExecutorLogic::executeTask($taskId, $dryRun);
  103. }
  104. /**
  105. * 为计划创建数据备份
  106. *
  107. * @param int $planId 计划ID
  108. * @param array $backupOptions 备份选项
  109. * @return array 备份结果
  110. */
  111. public static function createPlanBackup(int $planId, array $backupOptions = []): array
  112. {
  113. return BackupLogic::createPlanBackup($planId, $backupOptions);
  114. }
  115. /**
  116. * 为任务创建数据备份
  117. *
  118. * @param int $taskId 任务ID
  119. * @param array $backupOptions 备份选项
  120. * @return array 备份结果
  121. */
  122. public static function createTaskBackup(int $taskId, array $backupOptions = []): array
  123. {
  124. return BackupLogic::createTaskBackup($taskId, $backupOptions);
  125. }
  126. /**
  127. * 恢复数据备份
  128. *
  129. * @param int $backupId 备份ID
  130. * @param array $restoreOptions 恢复选项
  131. * @return array 恢复结果
  132. */
  133. public static function restoreBackup(int $backupId, array $restoreOptions = []): array
  134. {
  135. return BackupLogic::restoreBackup($backupId, $restoreOptions);
  136. }
  137. /**
  138. * 验证备份完整性
  139. *
  140. * @param int $backupId 备份ID
  141. * @return array 验证结果
  142. */
  143. public static function verifyBackup(int $backupId): array
  144. {
  145. return BackupLogic::verifyBackup($backupId);
  146. }
  147. /**
  148. * 获取任务执行进度
  149. *
  150. * @param int $taskId 任务ID
  151. * @return array 进度信息
  152. */
  153. public static function getTaskProgress(int $taskId): array
  154. {
  155. return CleanupTaskLogic::getTaskProgress($taskId);
  156. }
  157. /**
  158. * 停止任务执行
  159. *
  160. * @param int $taskId 任务ID
  161. * @return array 停止结果
  162. */
  163. public static function stopTask(int $taskId): array
  164. {
  165. return CleanupTaskLogic::stopTask($taskId);
  166. }
  167. /**
  168. * 暂停任务执行
  169. *
  170. * @param int $taskId 任务ID
  171. * @return array 暂停结果
  172. */
  173. public static function pauseTask(int $taskId): array
  174. {
  175. return CleanupTaskLogic::pauseTask($taskId);
  176. }
  177. /**
  178. * 恢复任务执行
  179. *
  180. * @param int $taskId 任务ID
  181. * @return array 恢复结果
  182. */
  183. public static function resumeTask(int $taskId): array
  184. {
  185. return CleanupTaskLogic::resumeTask($taskId);
  186. }
  187. /**
  188. * 启动任务执行
  189. *
  190. * @param int $taskId 任务ID
  191. * @return array 启动结果
  192. */
  193. public static function startTask(int $taskId): array
  194. {
  195. return CleanupTaskLogic::startTask($taskId);
  196. }
  197. /**
  198. * 取消任务执行
  199. *
  200. * @param int $taskId 任务ID
  201. * @param string $reason 取消原因
  202. * @return array 取消结果
  203. */
  204. public static function cancelTask(int $taskId, string $reason = ''): array
  205. {
  206. return CleanupTaskLogic::cancelTask($taskId, $reason);
  207. }
  208. /**
  209. * 获取清理统计信息
  210. *
  211. * @param array $filters 筛选条件
  212. * @return array 统计信息
  213. */
  214. public static function getCleanupStats(array $filters = []): array
  215. {
  216. return [
  217. 'plans' => CleanupPlan::getEnabledStats(),
  218. 'tasks' => CleanupTask::getStatusStats(),
  219. 'backups' => CleanupBackup::getStatusStats(),
  220. 'recent_tasks' => CleanupTask::getRecentStats(7),
  221. 'storage' => CleanupBackup::getStorageStats(),
  222. ];
  223. }
  224. /**
  225. * 清理过期备份
  226. *
  227. * @param int $retentionDays 保留天数
  228. * @return array 清理结果
  229. */
  230. public static function cleanExpiredBackups(int $retentionDays = 30): array
  231. {
  232. return BackupLogic::cleanExpiredBackups($retentionDays);
  233. }
  234. /**
  235. * 获取SQL备份列表
  236. *
  237. * @param array $filters 筛选条件
  238. * @return array SQL备份列表
  239. */
  240. public static function getSqlBackups(array $filters = []): array
  241. {
  242. $query = CleanupSqlBackup::with('backup');
  243. // 按备份ID筛选
  244. if (!empty($filters['backup_id'])) {
  245. $query->where('backup_id', $filters['backup_id']);
  246. }
  247. // 按表名筛选
  248. if (!empty($filters['table_name'])) {
  249. $query->where('table_name', 'like', '%' . $filters['table_name'] . '%');
  250. }
  251. // 按记录数量筛选
  252. if (!empty($filters['min_records'])) {
  253. $query->where('records_count', '>=', $filters['min_records']);
  254. }
  255. // 按内容大小筛选
  256. if (!empty($filters['min_size'])) {
  257. $query->where('content_size', '>=', $filters['min_size']);
  258. }
  259. // 排序
  260. $orderBy = $filters['order_by'] ?? 'created_at';
  261. $orderDirection = $filters['order_direction'] ?? 'desc';
  262. $query->orderBy($orderBy, $orderDirection);
  263. // 分页
  264. $perPage = $filters['per_page'] ?? 20;
  265. $result = $query->paginate($perPage);
  266. return [
  267. 'success' => true,
  268. 'data' => $result->items(),
  269. 'pagination' => [
  270. 'current_page' => $result->currentPage(),
  271. 'per_page' => $result->perPage(),
  272. 'total' => $result->total(),
  273. 'last_page' => $result->lastPage(),
  274. ]
  275. ];
  276. }
  277. /**
  278. * 获取SQL备份详情
  279. *
  280. * @param int $sqlBackupId SQL备份ID
  281. * @return array 备份详情
  282. */
  283. public static function getSqlBackupDetail(int $sqlBackupId): array
  284. {
  285. try {
  286. $sqlBackup = CleanupSqlBackup::with('backup')->findOrFail($sqlBackupId);
  287. return [
  288. 'success' => true,
  289. 'data' => [
  290. 'id' => $sqlBackup->id,
  291. 'backup_id' => $sqlBackup->backup_id,
  292. 'backup_name' => $sqlBackup->backup->backup_name ?? '',
  293. 'table_name' => $sqlBackup->table_name,
  294. 'records_count' => $sqlBackup->records_count,
  295. 'content_size' => $sqlBackup->content_size,
  296. 'formatted_size' => $sqlBackup->formatted_size,
  297. 'content_hash' => $sqlBackup->content_hash,
  298. 'sql_preview' => $sqlBackup->sql_preview,
  299. 'backup_conditions' => $sqlBackup->backup_conditions,
  300. 'created_at' => $sqlBackup->created_at,
  301. 'updated_at' => $sqlBackup->updated_at,
  302. ]
  303. ];
  304. } catch (\Exception $e) {
  305. return [
  306. 'success' => false,
  307. 'message' => '获取SQL备份详情失败: ' . $e->getMessage(),
  308. 'data' => null
  309. ];
  310. }
  311. }
  312. /**
  313. * 获取SQL备份内容
  314. *
  315. * @param int $sqlBackupId SQL备份ID
  316. * @return array 备份内容
  317. */
  318. public static function getSqlBackupContent(int $sqlBackupId): array
  319. {
  320. try {
  321. $sqlBackup = CleanupSqlBackup::findOrFail($sqlBackupId);
  322. return [
  323. 'success' => true,
  324. 'data' => [
  325. 'id' => $sqlBackup->id,
  326. 'table_name' => $sqlBackup->table_name,
  327. 'sql_content' => $sqlBackup->sql_content,
  328. 'records_count' => $sqlBackup->records_count,
  329. 'content_size' => $sqlBackup->content_size,
  330. ]
  331. ];
  332. } catch (\Exception $e) {
  333. return [
  334. 'success' => false,
  335. 'message' => '获取SQL备份内容失败: ' . $e->getMessage(),
  336. 'data' => null
  337. ];
  338. }
  339. }
  340. /**
  341. * 清理历史日志
  342. *
  343. * @param int $retentionDays 保留天数
  344. * @return array 清理结果
  345. */
  346. public static function cleanHistoryLogs(int $retentionDays = 30): array
  347. {
  348. return CleanupTaskLogic::cleanHistoryLogs($retentionDays);
  349. }
  350. /**
  351. * 获取系统健康状态
  352. *
  353. * @return array 健康状态
  354. */
  355. public static function getSystemHealth(): array
  356. {
  357. $runningTasks = CleanupTask::running()->count();
  358. $failedTasks = CleanupTask::byStatus(\App\Module\Cleanup\Enums\TASK_STATUS::FAILED->value)
  359. ->where('created_at', '>=', now()->subDay())
  360. ->count();
  361. $expiredBackups = CleanupBackup::expired()->count();
  362. $expiringSoonBackups = CleanupBackup::expiringSoon(3)->count();
  363. $health = 'good';
  364. $issues = [];
  365. if ($runningTasks > 5) {
  366. $health = 'warning';
  367. $issues[] = "有 {$runningTasks} 个任务正在运行,可能存在性能问题";
  368. }
  369. if ($failedTasks > 0) {
  370. $health = 'warning';
  371. $issues[] = "最近24小时内有 {$failedTasks} 个任务执行失败";
  372. }
  373. if ($expiredBackups > 0) {
  374. $health = 'warning';
  375. $issues[] = "有 {$expiredBackups} 个备份已过期,建议清理";
  376. }
  377. if ($expiringSoonBackups > 0) {
  378. $issues[] = "有 {$expiringSoonBackups} 个备份即将过期";
  379. }
  380. if ($failedTasks > 5) {
  381. $health = 'critical';
  382. }
  383. return [
  384. 'health' => $health,
  385. 'issues' => $issues,
  386. 'metrics' => [
  387. 'running_tasks' => $runningTasks,
  388. 'failed_tasks_24h' => $failedTasks,
  389. 'expired_backups' => $expiredBackups,
  390. 'expiring_soon_backups' => $expiringSoonBackups,
  391. ],
  392. ];
  393. }
  394. /**
  395. * 获取推荐的清理计划
  396. *
  397. * @return array 推荐计划
  398. */
  399. public static function getRecommendedPlans(): array
  400. {
  401. $recommendations = [];
  402. // 检查是否有大量日志数据
  403. $logTables = \App\Module\Cleanup\Models\CleanupConfig::byCategory(
  404. \App\Module\Cleanup\Enums\DATA_CATEGORY::LOG_DATA->value
  405. )->get();
  406. if ($logTables->count() > 0) {
  407. $recommendations[] = [
  408. 'type' => 'category',
  409. 'title' => '日志数据清理',
  410. 'description' => '清理系统中的日志数据,释放存储空间',
  411. 'config' => [
  412. 'plan_type' => \App\Module\Cleanup\Enums\PLAN_TYPE::CATEGORY->value,
  413. 'target_selection' => [
  414. 'selection_type' => 'category',
  415. 'categories' => [\App\Module\Cleanup\Enums\DATA_CATEGORY::LOG_DATA->value],
  416. ],
  417. ],
  418. 'estimated_tables' => $logTables->count(),
  419. ];
  420. }
  421. // 检查是否有缓存数据
  422. $cacheTables = \App\Module\Cleanup\Models\CleanupConfig::byCategory(
  423. \App\Module\Cleanup\Enums\DATA_CATEGORY::CACHE_DATA->value
  424. )->get();
  425. if ($cacheTables->count() > 0) {
  426. $recommendations[] = [
  427. 'type' => 'category',
  428. 'title' => '缓存数据清理',
  429. 'description' => '清理系统中的缓存数据,提高系统性能',
  430. 'config' => [
  431. 'plan_type' => \App\Module\Cleanup\Enums\PLAN_TYPE::CATEGORY->value,
  432. 'target_selection' => [
  433. 'selection_type' => 'category',
  434. 'categories' => [\App\Module\Cleanup\Enums\DATA_CATEGORY::CACHE_DATA->value],
  435. ],
  436. ],
  437. 'estimated_tables' => $cacheTables->count(),
  438. ];
  439. }
  440. return $recommendations;
  441. }
  442. }