在Laravel的异步任务体系中,队列优先级是协调不同任务执行顺序的重要机制,邮件发送作为非核心即时任务,设置中等优先级可以平衡系统资源分配,既不会让邮件任务阻塞支付、订单处理等高优先级任务,也不会像低优先级日志任务那样长时间等待。

Laravel队列优先级的基本原理
Laravel的队列系统支持为不同任务分配优先级,底层依赖队列驱动的配置实现。Redis、数据库等常用队列驱动都支持优先级设置,核心逻辑是为不同优先级的任务分配不同的队列名称,然后在队列处理器启动时指定处理的队列顺序,优先级高的队列会先被消费。
默认情况下,Laravel的队列任务会进入default队列,所有任务优先级相同。要实现优先级区分,我们需要自定义队列名称,比如高优先级队列命名为high,中等优先级命名为medium,低优先级命名为low。
配置队列驱动与优先级队列
首先打开config/queue.php配置文件,确认队列驱动已经正确设置,这里以Redis驱动为例,默认配置如下:
<?php
return [
'default' => env('QUEUE_CONNECTION', 'redis'),
'connections' => [
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => null,
],
],
];
我们不需要修改驱动配置,只需要在后续任务分发时指定自定义队列名称即可。
创建邮件发送任务类
首先使用Artisan命令创建一个邮件发送任务类:
php artisan make:job SendEmailJob
生成的任务类位于app/Jobs/SendEmailJob.php,我们修改这个类,实现邮件发送逻辑,并指定任务进入中等优先级队列:
<?php
namespace AppJobs;
use IlluminateBusQueueable;
use IlluminateContractsQueueShouldQueue;
use IlluminateFoundationBusDispatchable;
use IlluminateQueueInteractsWithQueue;
use IlluminateQueueSerializesModels;
use IlluminateSupportFacadesMail;
use AppMailTestMail;
class SendEmailJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $toEmail;
protected $content;
/**
* 初始化任务参数
* @param string $toEmail 收件人邮箱
* @param string $content 邮件内容
*/
public function __construct($toEmail, $content)
{
$this->toEmail = $toEmail;
$this->content = $content;
// 指定任务进入中等优先级队列
$this->onQueue('medium');
}
/**
* 执行任务
*/
public function handle()
{
// 发送邮件逻辑
Mail::to($this->toEmail)->send(new TestMail($this->content));
}
}
这里通过$this->onQueue('medium')方法,将当前邮件发送任务指定到medium队列,也就是我们定义的中等优先级队列。
创建邮件类
接下来创建对应的邮件类,用于定义邮件内容:
php artisan make:mail TestMail
修改app/Mail/TestMail.php文件:
<?php
namespace AppMail;
use IlluminateBusQueueable;
use IlluminateMailMailable;
use IlluminateQueueSerializesModels;
class TestMail extends Mailable
{
use Queueable, SerializesModels;
protected $content;
/**
* 初始化邮件内容
* @param string $content 邮件正文
*/
public function __construct($content)
{
$this->content = $content;
}
/**
* 构建邮件
*/
public function build()
{
return $this->subject('测试邮件')
->view('emails.test')
->with(['content' => $this->content]);
}
}
同时创建对应的邮件视图文件resources/views/emails/test.blade.php:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试邮件</title>
</head>
<body>
<p>邮件内容:{{ $content }}</p>
</body>
</html>
分发邮件发送任务
在业务代码中需要发送邮件的位置,分发我们创建的SendEmailJob任务即可:
<?php
namespace AppHttpControllers;
use IlluminateHttpRequest;
use AppJobsSendEmailJob;
class TestController extends Controller
{
public function sendEmail(Request $request)
{
$toEmail = $request->input('email');
$content = '这是一封测试邮件,通过Laravel队列中等优先级发送';
// 分发邮件发送任务
SendEmailJob::dispatch($toEmail, $content);
return response()->json(['message' => '邮件任务已加入队列']);
}
}
启动队列处理器指定优先级顺序
任务分发后,需要启动队列处理器来消费队列,这里要指定队列的处理顺序,让高优先级队列先被处理,中等优先级次之,低优先级最后:
php artisan queue:work --queue=high,medium,low
这个命令的含义是队列处理器会先处理high队列中的任务,当high队列为空时,再处理medium队列的任务,最后处理low队列的任务,这样就实现了优先级控制,我们的邮件发送任务在medium队列,属于中等优先级。
验证优先级效果
我们可以做简单的测试,同时分发高优先级任务、邮件中等优先级任务、低优先级任务,观察执行顺序:
<?php
// 测试优先级顺序
// 高优先级任务
dispatch(function () {
logger('高优先级任务执行');
})->onQueue('high');
// 中等优先级邮件任务
SendEmailJob::dispatch('test@ipipp.com', '中等优先级邮件测试');
// 低优先级任务
dispatch(function () {
logger('低优先级任务执行');
})->onQueue('low');
启动队列处理器后,查看日志可以看到执行顺序是:高优先级任务先执行,然后是邮件中等优先级任务,最后是低优先级任务,说明中等优先级设置生效。
注意事项
- 如果使用数据库队列驱动,需要确认
jobs表的queue字段可以正常存储自定义队列名称,Laravel默认数据库队列配置支持自定义队列。 - 队列处理器启动时可以指定
--tries参数设置任务失败重试次数,邮件任务建议设置合理的重试次数,避免邮件重复发送。 - 如果系统任务量较大,可以启动多个队列处理器,部分处理器专门处理高优先级队列,提升高优先级任务的消费速度。