Laravel自定义Artisan命令:大嵌套文件与数据集的内存友好清理
自定义Artisan命令清理文件系统问题解决
问题概述
构建每日清理文件系统的自定义Artisan命令,涉及大量文件夹与用户,存在内存崩溃问题,需完成:
- 筛选创建时间超过50天的日期文件夹
- 提取嵌套的用户ID,查询用户并检查
$user->isCompleted() - 若用户数据已完成,删除对应目录
目录结构
存储格式:
data/<date>/<user_id>
示例:
data/2022-01-15/7482947 data/2022-01-15/7482946 data/2022-01-15/7482945 data/2022-01-16/2353234 data/2022-01-16/2353233 data/2022-01-16/2353232
现有代码
已筛选出过期日期文件夹,但无法处理用户子目录与数据库查询:
collect(Storage::directories('data/')) ->filter(function ($directory) { $directoryDate = Str::after($directory, '/'); if (! Carbon::parse($directoryDate)->lte(now()->subDays(50))) { return false; } return true; });
解决方案
核心优化:分批处理+避免内存过载
不要一次性加载所有目录到集合,改用循环遍历+数据库chunk查询,减少内存占用。完整命令代码如下:
<?php namespace App\Console\Commands; use Illuminate\Console\Command; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Carbon; use Illuminate\Support\Str; use App\Models\User; class CleanupUserData extends Command { protected $signature = 'cleanup:user-data'; protected $description = 'Clean up user data directories for completed users (data older than 50 days)'; public function handle() { $cutoffDate = now()->subDays(50); $dateDirectories = Storage::directories('data/'); foreach ($dateDirectories as $dateDir) { $dateStr = Str::afterLast($dateDir, '/'); // 跳过无效或未过期的日期目录 try { $dirDate = Carbon::parse($dateStr); if ($dirDate->gt($cutoffDate)) continue; } catch (\Exception $e) { $this->warn("Skip invalid date directory: $dateDir"); continue; } // 获取当前日期下的所有用户目录 $userDirs = Storage::directories($dateDir); $userIds = collect($userDirs)->map(fn($dir) => Str::afterLast($dir, '/')) ->filter(fn($id) => is_numeric($id)) ->toArray(); if (empty($userIds)) continue; // 分批查询用户,避免内存溢出 User::whereIn('id', $userIds)->chunk(100, function ($users) use ($dateDir) { foreach ($users as $user) { if ($user->isCompleted()) { $targetDir = "$dateDir/{$user->id}"; if (Storage::exists($targetDir)) { Storage::deleteDirectory($targetDir); $this->info("Deleted: $targetDir"); } } } }); } $this->info('Cleanup finished.'); return 0; } }
额外优化建议
- 队列异步处理:将每个日期目录的处理任务推入队列,分时段执行,进一步降低内存压力。
- 添加执行锁:用Cache设置命令执行锁,防止同一时间多次运行导致冲突。
- 日志记录:记录删除操作和异常情况,便于后续排查。
- 测试验证:先在测试环境验证逻辑,确保不会误删有效数据。
内容的提问来源于stack exchange,提问作者BigJobbies
相关产品推荐
相关产品推荐

