在 .env
文件中配置队列驱动:
QUEUE_CONNECTION=redis # 使用 Redis 作为队列驱动
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
支持的驱动包括:sync
(同步执行,用于测试)、database
、redis
、beanstalkd
、sqs
等。
使用 Artisan 命令生成任务类:
php artisan make:job ProcessImage
任务类位于 app/Jobs
目录,默认结构如下:
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ProcessImage implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $imagePath;
public function __construct($imagePath)
{
$this->imagePath = $imagePath;
}
public function handle()
{
// 处理图像的逻辑
\Image::make($this->imagePath)
->resize(300, 300)
->save(public_path('resized/' . basename($this->imagePath)));
}
}
在控制器或服务中分发任务:
// 立即执行任务
ProcessImage::dispatch($imagePath);
// 指定队列名称
ProcessImage::dispatch($imagePath)->onQueue('images');
// 延迟执行任务(10分钟后)
ProcessImage::dispatch($imagePath)->delay(now()->addMinutes(10));
任务类中添加 failed
方法处理失败情况:
public function failed(Exception $exception)
{
// 记录失败日志
Log::error('图像处理失败: ' . $exception->getMessage());
// 发送通知
Notification::send($this->user, new ImageProcessingFailed($this->imagePath));
}
使用 Artisan 命令启动队列工作进程:
php artisan queue:work --daemon # 守护进程模式
php artisan queue:work --once # 只处理一个任务后退出
php artisan queue:work --tries=3 # 每个任务最多尝试3次
推荐使用进程管理器(如 Supervisor)确保工作进程持续运行:
; /etc/supervisor/conf.d/laravel-worker.conf
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /path/to/your-project/artisan queue:work --daemon --tries=3
autostart=true
autorestart=true
numprocs=3 # 启动3个工作进程
user=www-data
redirect_stderr=true
stdout_logfile=/path/to/your-project/storage/logs/worker.log
更新配置并重启 Supervisor:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker:*
在任务类中设置最大尝试次数和退避策略:
class ProcessImage implements ShouldQueue
{
public $tries = 3; // 最多尝试3次
public $backoff = [30, 60, 120]; // 每次重试的延迟时间(秒)
// 或动态计算退避时间
public function backoff()
{
return [10, 30, 60];
}
}
在任务的 handle
方法中手动控制重试:
public function handle()
{
try {
// 尝试执行任务
$response = Http::get('https://api.example.com');
if ($response->failed()) {
throw new Exception('API 请求失败');
}
} catch (Exception $e) {
// 检查是否已达到最大重试次数
if ($this->attempts() > 3) {
$this->fail($e);
return;
}
// 记录重试日志
Log::warning("任务重试中: {$this->attempts()} 次尝试");
// 延迟后重试
$this->release(10); // 10秒后重试
}
}
在分发任务时指定队列优先级:
// 高优先级队列
ProcessImage::dispatch($imagePath)->onQueue('high');
// 低优先级队列
SendEmail::dispatch($email)->onQueue('low');
启动工作进程时指定队列处理顺序:
php artisan queue:work --daemon --queue=high,default,low
在 config/queue.php
中配置队列连接和优先级:
'connections' => [
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => null,
],
],
'priorities' => [
'high' => ['high', 'images'],
'medium' => ['default'],
'low' => ['emails', 'notifications'],
],
Laravel 提供多种灵活的分发方式:
// 基本分发
ProcessImage::dispatch($path);
// 指定队列和延迟时间
ProcessImage::dispatch($path)
->onQueue('high')
->delay(now()->addMinutes(5));
// 链式分发多个任务
ProcessImage::dispatch($path)
->chain([
new OptimizeImage($path),
new NotifyUser($path),
]);
// 批量分发任务
$batch = Bus::batch([
new ProcessImage($path1),
new ProcessImage($path2),
])->then(function ($batch) {
// 所有任务成功完成
})->dispatch();
任务类的 handle
方法包含核心逻辑,支持中间件和管道:
public function handle()
{
// 处理逻辑
$image = Image::make($this->imagePath);
$image->resize(300, 300)->save($this->outputPath);
// 更新数据库
$this->updateImageRecord();
}
// 任务中间件
public function middleware()
{
return [new LogJobProcessing];
}
通过 failed
方法和全局事件监听处理失败任务:
public function failed(Exception $exception)
{
// 记录失败日志
logger()->error("任务失败: {$exception->getMessage()}");
// 发送通知
Notification::route('slack', config('services.slack.webhook'))
->notify(new JobFailedNotification($this, $exception));
}
// 全局事件监听
protected $listen = [
JobFailed::class => [
'App\Listeners\LogFailedJob',
],
];
Laravel Horizon 是官方提供的队列监控仪表盘:
composer install laravel/horizon
php artisan horizon:install
php artisan horizon
访问 http://your-app/horizon
查看队列状态、任务统计和失败任务。
在任务中记录自定义指标:
public function handle()
{
$startTime = microtime(true);
// 执行任务逻辑
$executionTime = microtime(true) - $startTime;
// 记录执行时间
Redis::zadd('task_execution_times', $executionTime, class_basename($this));
}
查看和管理失败任务:
php artisan queue:failed
php artisan queue:retry {id}
php artisan queue:forget {id}
php artisan queue:flush
使用任务批处理执行一组相关任务:
$batch = Bus::batch([
new ProcessImage($path1),
new ProcessImage($path2),
])->then(function ($batch) {
// 所有任务成功完成
})->catch(function ($batch, $e) {
// 至少一个任务失败
})->dispatch();
使用任务管道处理一系列关联任务:
(new ProcessImage($path))
->through([
new ValidateImage,
new ResizeImage,
new WatermarkImage,
])
->dispatch();
监听队列事件执行额外逻辑:
protected $listen = [
'Illuminate\Queue\Events\JobProcessing' => [
'App\Listeners\LogJobProcessing',
],
'Illuminate\Queue\Events\JobProcessed' => [
'App\Listeners\LogJobProcessed',
],
];
选择合适的队列驱动:
优化工作进程配置:
--memory
选项限制工作进程内存使用实现任务幂等性:
监控队列长度:
Laravel 的异步任务系统提供了强大而灵活的解决方案,能够显著提升应用的响应速度和稳定性。通过合理配置队列驱动、优化任务处理逻辑、实现智能重试机制和完善的监控体系,可以构建出高性能、可扩展的应用系统。
在实际项目中,建议根据业务需求选择合适的队列驱动和配置策略,优先处理关键任务,并通过 Horizon 等工具实时监控队列状态。合理使用任务批处理、管道和事件监听等高级特性,可以进一步提升系统的可维护性和可靠性。