CleanupService.php 13 KB

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