首页 留言板 后台管理

搜索中...

未找到与 "" 相关的文章

换个关键词试试看

输入关键词搜索文章

支持搜索标题、内容、摘要

Laravel 队列系统详解:异步任务、延迟执行与监控

admin · 2026-04-28 14:14 · Laravel · 2

在 Web 应用开发中,某些操作(如发送邮件、生成报表、处理图片)耗时较长,如果在请求生命周期内同步执行,会严重影响用户体验。Laravel 队列系统提供了一套优雅的解决方案,允许我们将耗时任务推送到后台异步执行,从而显著提升应用响应速度。

本文将从队列驱动配置、任务创建与分发、延迟执行、任务链到队列监控,系统讲解 Laravel 队列的完整使用方案。

什么是队列

队列(Queue)是一种异步处理机制。简单来说,就是将任务先存起来,等到有可用 worker 时再取出来执行。在 Laravel 中,队列的核心流程如下:

  1. 创建任务(Job):定义需要异步执行的逻辑
  2. 分发任务(Dispatch):将任务推送到队列存储(如 Redis、数据库)
  3. 消费任务(Work):队列 worker 从存储中取出任务并执行

配置队列驱动

Laravel 支持多种队列驱动:

驱动 说明 适用场景
sync 同步执行 本地开发调试
database 数据表存储 小型项目,无 Redis 环境
redis Redis 存储 生产环境首选,性能优秀
beanstalkd Beanstalkd 轻量级消息队列
sqs AWS SQS 云原生部署

推荐生产环境使用 Redis 驱动,配置 .env

QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379

如果使用数据库驱动,需先执行迁移创建任务表:

php artisan queue:table
php artisan migrate

创建任务类

使用 Artisan 命令生成任务类:

php artisan make:job SendWelcomeEmail

生成的 app/Jobs/SendWelcomeEmail.php

<?php

namespace App\Jobs;

use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
use App\Mail\WelcomeMail;

class SendWelcomeEmail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(
        public User $user
    ) {}

    public function handle(): void
    {
        Mail::to($this->user->email)
            ->send(new WelcomeMail($this->user));
    }
}

ShouldQueue 接口是队列任务的核心标识。任务类中的 handle() 方法包含实际执行业务逻辑。SerializesModels trait 会自动序列化/反序列化 Eloquent 模型,非常便利。

分发任务

在控制器或服务中,一行代码即可将任务推送到队列:

use App\Jobs\SendWelcomeEmail;

// 默认队列
SendWelcomeEmail::dispatch($user);

// 指定队列名称
SendWelcomeEmail::dispatch($user)->onQueue('emails');

// 延迟执行(10 分钟后)
SendWelcomeEmail::dispatch($user)->delay(now()->addMinutes(10));

延迟执行

延迟执行是队列的常用场景。例如,用户注册后不立即发送欢迎邮件,而是等待 5 分钟:

SendWelcomeEmail::dispatch($user)
    ->delay(now()->addMinutes(5));

或者指定具体时间点:

SendWelcomeEmail::dispatch($user)
    ->delay(now()->addHours(2));

任务链与批处理

任务链

任务链允许按顺序执行多个任务,前一个失败则后续停止:

use Illuminate\Support\Facades\Bus;

Bus::chain([
    new OptimizeImage($image),
    new GenerateThumbnail($image),
    new NotifyUser($user),
])->dispatch();

任务批处理

Laravel 8+ 支持批量分发任务,可统一监控完成状态:

use Illuminate\Bus\Batch;
use Illuminate\Support\Facades\Bus;

$batch = Bus::batch([
    new ImportCsvRow($row1),
    new ImportCsvRow($row2),
    new ImportCsvRow($row3),
])->then(function (Batch $batch) {
    // 所有任务成功完成
})->catch(function (Batch $batch, Throwable $e) {
    // 首次失败时触发
})->dispatch();

队列 Worker

启动队列 worker 消费任务:

# 基础启动
php artisan queue:work

# 指定连接和队列
php artisan queue:work redis --queue=emails,default

# 处理一个任务后退出(适合 cron)
php artisan queue:work --once

# 不重启持续运行(生产环境)
php artisan queue:work --sleep=3 --tries=3

重要:开发环境使用 queue:listen(修改代码自动生效),生产环境使用 queue:work(启动后常驻内存,性能更高)。

Supervisor 配置

生产环境建议使用 Supervisor 守护队列进程:

[program:snowmanblog-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /www/wwwroot/snowmanblog/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/var/log/snowmanblog-worker.log

失败任务处理

任务执行失败时,Laravel 会自动记录到 failed_jobs 表。查看失败任务:

php artisan queue:failed

重试指定失败任务:

php artisan queue:retry 1

重试所有失败任务:

php artisan queue:retry all

在任务类中自定义失败逻辑:

public function failed(\Throwable $exception): void
{
    \Log::error('发送欢迎邮件失败', [
        'user_id' => $this->user->id,
        'error' => $exception->getMessage(),
    ]);
}

最佳实践

  1. 保持任务轻量:避免在 handle() 中执行大量复杂逻辑,应拆分为多个小任务
  2. 合理设置超时:在任务类中定义 $timeout 属性,防止长时间挂起
  3. 幂等性设计:任务可能被重试,确保多次执行不会产生副作用
  4. 监控队列长度:定期检查队列积压情况,及时调整 worker 数量
  5. 区分队列优先级:将邮件、通知等分为不同队列,优先处理核心任务

总结

Laravel 队列系统为异步处理提供了开箱即用的解决方案。从简单的邮件发送,到复杂的批量数据处理,队列都能游刃有余。合理使用队列不仅能提升用户体验,还能有效削峰填谷,保障系统在高并发场景下的稳定性。

如果你的项目尚未引入队列,不妨从发送邮件或生成报表这类非实时任务开始尝试,逐步感受异步编程带来的性能提升。

评论 (0)

暂无评论,来说两句吧!

发表评论

支持 Markdown 语法和 Emoji 😀