Laravel清理用定时脚本吗

wen PHP项目 19

本文目录导读:

Laravel清理用定时脚本吗

  1. 常见需要清理的场景
  2. 实现方式
  3. 设置 crontab(仅需一行)
  4. 最佳实践建议
  5. 示例:完整的清理策略

在 Laravel 中,清理任务通常使用定时任务(调度任务)来实现,而不是直接用 Linux 的 crontab 写复杂脚本,Laravel 的 schedule 机制本质上还是基于 crontab,但提供了更优雅、更项目内聚的管理方式。

常见需要清理的场景

  1. 日志文件 - storage/logs/laravel.log 过大
  2. 会话文件 - storage/framework/sessions/ 过期会话
  3. 缓存文件 - 视图缓存、数据缓存
  4. 临时上传文件 - 未使用的临时文件
  5. 数据库过期数据 - 旧日志、软删除数据等
  6. 活动日志/通知 - 过期的活动记录

实现方式

使用 Laravel 内置的 Schedule(推荐)

app/Console/Kernel.phpschedule 方法中定义清理任务:

// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
    // 清理过期会话(每天一次)
    $schedule->command('session:clean')
             ->daily();
    // 清理模型过期数据(每天凌晨2点)
    $schedule->call(function () {
        // 删除30天前的日志
        ActivityLog::where('created_at', '<', now()->subDays(30))->delete();
        // 硬删除软删除超过30天的数据
        Post::onlyTrashed()
            ->where('deleted_at', '<', now()->subDays(30))
            ->forceDelete();
    })->dailyAt('02:00');
    // 清理临时文件(每小时)
    $schedule->command('telescope:prune --hours=48')
             ->hourly();
    // 使用 Artisan 命令清理(自定义命令)
    $schedule->command('logs:clean')
             ->weekly()
             ->appendOutputTo(storage_path('logs/cleanup.log'));
}

创建自定义 Artisan 命令

如果清理逻辑复杂,建议创建独立的 Artisan 命令:

php artisan make:command CleanExpiredData
// app/Console/Commands/CleanExpiredData.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class CleanExpiredData extends Command
{
    protected $signature = 'app:clean-expired-data 
                            {--days=30 : 保留天数}
                            {--type=all : 清理类型(logs,sessions,db,all)}';
    protected $description = '清理过期数据';
    public function handle()
    {
        $days = $this->option('days');
        $type = $this->option('type');
        if ($type === 'logs' || $type === 'all') {
            $this->cleanLogs($days);
        }
        if ($type === 'sessions' || $type === 'all') {
            $this->cleanSessions();
        }
        if ($type === 'db' || $type === 'all') {
            $this->cleanDatabase($days);
        }
        $this->info('清理完成!');
    }
    protected function cleanLogs($days)
    {
        // 清理 storage/logs 中的旧日志
        $logFiles = glob(storage_path('logs/*.log'));
        foreach ($logFiles as $file) {
            if (filemtime($file) < now()->subDays($days)->timestamp) {
                unlink($file);
                $this->line("删除日志文件: " . basename($file));
            }
        }
    }
    protected function cleanSessions()
    {
        // Laravel 会自动清理 sessions,但可以手动触发
        $this->call('session:clean');
    }
    protected function cleanDatabase($days)
    {
        // 清理过期记录
        InactiveUser::where('last_login', '<', now()->subDays($days))->delete();
        TempUpload::where('created_at', '<', now()->subDay())->delete();
    }
}

然后在 Kernel.php 中调度:

$schedule->command('app:clean-expired-data --days=30 --type=all')
         ->dailyAt('03:00')
         ->onOneServer(); // 多台服务器时防止重复执行

使用队列任务(适合大批量清理)

对于大量数据清理,建议使用队列,避免阻塞主进程:

// 在 Kernel 中
$schedule->job(new \App\Jobs\CleanExpiredData(['days' => 30]))
         ->daily()
         ->withoutOverlapping(60); // 防止重复,锁60分钟
// app/Jobs/CleanExpiredData.php
public function handle()
{
    // 分批删除,避免锁表
    Post::where('expires_at', '<', now())
        ->chunkById(100, function ($posts) {
            foreach ($posts as $post) {
                $post->delete(); // 如果有事件监听
            }
        });
    // 或者使用 each 分批
    TempFile::where('created_at', '<', now()->subDay())
            ->each(function ($file) {
                Storage::delete($file->path);
                $file->delete();
            }, 100);
}

设置 crontab(仅需一行)

在服务器上设置 crontab 即可,不需要为每个任务单独设置 cron

# 每天执行 Laravel 调度器
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

Laravel 的 Schedule 会根据你定义的时间频率自动决定何时执行。

最佳实践建议

建议 说明
频率合理 日志每天清理,临时文件每小时,数据库过期数据每天
时间选择 避免高峰期,建议凌晨02:00-05:00
防止重叠 使用 withoutOverlapping() 防止任务重叠
监控日志 使用 appendOutputTo() 记录执行日志
测试优先 先在测试环境运行 php artisan schedule:test 测试
分批处理 大数据量使用 chunk 或队列,避免内存溢出
异常处理 在命令或 Job 中添加 try-catch 和通知
多服务器 使用 onOneServer() 防止多台服务器重复执行

示例:完整的清理策略

protected function schedule(Schedule $schedule)
{
    // 每天凌晨3点清理
    $schedule->command('queue:prune-failed --hours=48')
             ->dailyAt('03:00');
    // 每周清理旧日志
    $schedule->exec('find ' . storage_path('logs') . ' -name "*.log" -mtime +7 -delete')
             ->weekly()
             ->onOneServer();
    // 每天清理数据库过期数据
    $schedule->call(function () {
        // 批量删除,记录日志
        $deleted = OldRecords::where('created_at', '<', now()->subMonths(6))
                             ->delete();
        Log::info("清理了 {$deleted} 条旧记录");
    })->dailyAt('04:00')
      ->withoutOverlapping(60)
      ->appendOutputTo(storage_path('logs/scheduled-clean.log'));
}
  • 用 Laravel Schedule 管理清理任务(推荐)
  • 创建自定义 Artisan 命令 组织复杂逻辑
  • 设置 crontab* * * * * php artisan schedule:run
  • 合理分配频率 和时间,使用 withoutOverlapping
  • 测试命令 php artisan schedule:test 模拟执行

Laravel 的定时任务机制让清理工作变得非常整洁和可维护,而且可以充分利用 Laravel 的 ORM、事件、队列等功能来安全高效地执行。

抱歉,评论功能暂时关闭!