本文目录导读:

在 Laravel 中,队列的延迟执行和优先级是两个重要的功能特性,让我详细介绍这两个功能的实现方法和最佳实践。
延迟执行(Delayed Processing)
基本用法
<?php
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 SendWelcomeEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $user;
public function __construct($user)
{
$this->user = $user;
}
public function handle()
{
// 执行任务
}
}
设置延迟时间
// 方法1:在分发时指定延迟 use App\Jobs\SendWelcomeEmail; use Illuminate\Support\Facades\Queue; // 延迟5秒后执行 SendWelcomeEmail::dispatch($user)->delay(now()->addSeconds(5)); // 延迟10分钟 SendWelcomeEmail::dispatch($user)->delay(now()->addMinutes(10)); // 延迟到指定时间 SendWelcomeEmail::dispatch($user)->delay(now()->addDay());
在 Job 类中定义默认延迟
class SendWelcomeEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// 定义默认延迟时间
public $delay = 60; // 60秒
// 或者使用方法
public function delay()
{
return now()->addMinutes(5);
}
public function handle()
{
// 执行任务
}
}
条件延迟
// 根据条件设置不同延迟 $delay = $user->isNew() ? now()->addMinutes(30) : now()->addHours(1); SendWelcomeEmail::dispatch($user)->delay($delay);
优先级设置(Queue Priority)
配置不同队列
// config/queue.php
'connections' => [
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => 0,
],
],
使用不同队列名称
// 分发到指定队列
use App\Jobs\ProcessPayment;
use App\Jobs\SendEmail;
// 高优先级队列
ProcessPayment::dispatch($order)->onQueue('high');
ProcessPayment::dispatch($order)->onQueue('high')->delay(now()->addMinutes(5));
// 普通优先级队列
SendEmail::dispatch($user)->onQueue('default');
// 低优先级队列
ProcessImage::dispatch($image)->onQueue('low');
在 Job 类中指定队列
class ProcessPayment implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// 在构造函数中指定
public function __construct($order)
{
$this->onQueue('high');
}
// 或使用属性
public $queue = 'high';
public function handle()
{
// 处理订单
}
}
多队列监听配置
# 启动多个队列处理器(注意优先级顺序) php artisan queue:work --queue=high,default,low
在 Supervisor 配置中管理优先级
; supervisor.conf [program:laravel-high-queue] process_name=%(program_name)s_%(process_num)02d command=php /path/to/artisan queue:work redis --queue=high --tries=3 --max-time=3600 numprocs=2 autostart=true autorestart=true stopasgroup=true killasgroup=true user=forge redirect_stderr=true stdout_logfile=/path/to/logs/worker.log [program:laravel-low-queue] process_name=%(program_name)s_%(process_num)02d command=php /path/to/artisan queue:work redis --queue=low --tries=3 --max-time=3600 numprocs=1 autostart=true autorestart=true stopasgroup=true killasgroup=true user=forge redirect_stderr=true stdout_logfile=/path/to/logs/worker.log
高级应用示例
定时任务中的延迟队列
// App\Console\Kernel.php
protected function schedule(Schedule $schedule)
{
// 每天凌晨3点执行
$schedule->call(function () {
// 处理大量数据
$users = User::where('status', 'active')->get();
foreach ($users as $user) {
// 分批次延迟执行
GenerateReport::dispatch($user)
->onQueue('report')
->delay(now()->addMinutes($user->id % 60));
}
})->dailyAt('03:00');
}
带重试策略的延迟队列
class ProcessData implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 3;
public $timeout = 120;
public $backoff = [2, 10, 30]; // 重试间隔
public function handle()
{
try {
// 处理数据
} catch (\Exception $e) {
// 特定错误时重新延迟
if ($this->attempts() < 3) {
$this->release(now()->addMinutes(10));
} else {
throw $e;
}
}
}
}
动态优先级调整
class ManagePriorityQueue
{
public function adjustPriority(Job $job, $newPriority)
{
// 重新分配队列
$className = get_class($job);
$className::dispatch(...$job->getOriginal())
->onQueue($newPriority)
->delay(now()->addSeconds(5));
// 删除原任务
$job->delete();
}
}
Redis 队列优先级示例
// config/queue.php - 使用 Redis 的优先级支持
'connections' => [
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => [
'high',
'default',
'low',
],
'retry_after' => 90,
'block_for' => 0,
],
],
监控和测试
查看队列状态
# 查看队列监控 php artisan queue:monitor high,default,low php artisan queue:failed --limit=10
在代码中监控
// 使用事件监听队列状态
Queue::before(function (JobProcessing $event) {
Log::info('Job processing: ' . $event->job->getName());
});
Queue::after(function (JobProcessed $event) {
Log::info('Job processed: ' . $event->job->getName());
});
Queue::failing(function (JobFailed $event) {
Log::error('Job failed: ' . $event->job->getName());
});
测试队列
public function test_delayed_job()
{
Queue::fake();
SendWelcomeEmail::dispatch($user)->delay(now()->addMinutes(10));
Queue::assertPushed(SendWelcomeEmail::class, function ($job) {
return $job->delay->format('Y-m-d H:i') === now()->addMinutes(10)->format('Y-m-d H:i');
});
}
最佳实践
- 合理设置延迟时间:避免过长的延迟导致任务堆积
- 配置合适的 worker 数量:根据业务需求调整各优先级队列的 worker 数量
- 监控队列性能:定期检查队列长度和处理时间
- 错误处理:设置合理的重试次数和延迟重试策略
- 性能优化:对于大数据量任务,分批延迟执行避免资源耗尽
通过合理使用延迟和优先级,可以有效地控制系统资源分配,确保关键任务优先处理,同时避免系统过载。