消息队列的主要特点是异步处理,主要目的是减少请求响应时间和解耦。所以主要的使用场景就是将比较耗时而且不需要即时(同步)返回结果的操作作为消息放入消息队列。同时由于使用了消息队列,只要保证消息格式不变,消息的发送方和接收方并不需要彼此联系,也不需要受对方的影响,即解耦和。
配置队列
安装扩展包
代码语言:javascript复制composer require "predis/predis:~1.0"
队列的配置信息存放在config/queue.php 在.env中修改配置驱动 QUEUE_DRIVER=redis
使用redis驱动 REDIS_CLIENT=predis
使用predis
生成队列需要的数据表
有时候队列会执行失败,这张表用于存放失败信息
代码语言:javascript复制php artisan queue:failed-table
php artisan migrate
生成任务类
生成的文件存放在 appJobs
代码语言:javascript复制php artisan make:jon QueueName
该文件有两个方法 _construct
构造方法 注入模型 handler
任务的逻辑
<?php
namespace AppJobs;
use IlluminateBusQueueable;
use IlluminateQueueSerializesModels;
use IlluminateQueueInteractsWithQueue;
use IlluminateContractsQueueShouldQueue;
use IlluminateFoundationBusDispatchable;
use AppModelsTopic;
use AppHandlersTranslateHandler;
class TranslateSlug implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $topic;
public function __construct(Topic $topic)
{
// 队列任务构造器中接收了 Eloquent 模型,将会只序列化模型的 ID
$this->topic = $topic;
}
public function handle()
{
// 请求百度 API 接口进行翻译
$slug = app(AppHandlersTranslateHandler::class)->translate($this->topic->title);
// 为了避免模型监控器死循环调用,我们使用 DB 类直接对数据库进行操作
DB::table('topics')->where('id', $this->topic->id)->update(['slug' => $slug]);
}
}
注意
若任务涉及到了数据库的读写,需要注意 数据库的读写直接使用 DB 类,而不是使用 ORM 因为一般我们会在模型监听器中分发队列任务,此时,会形成一个死循环 通过 ORM 写数据库,触发 ORM 监听器 -> 分发队列任务 -> 任务中使用了 ORM 写数据库 -> 通过 ORM 写数据库,触发 ORM 监听器 -> ....
分发任务
调用 dispatch(new QueueName($model))
将任务放在默认的队列上
public function saved(Topic $topic)
{
// 如 slug 字段无内容,即使用翻译器对 title 进行翻译
if ( ! $topic->slug) {
// 推送任务到队列
dispatch(new TranslateSlug($topic));
}
}
队列监控
1.通过命令监控
代码语言:javascript复制php artisan queue:listen
2.有图形界面的监控 Horizon 安装Horizon
代码语言:javascript复制composer require "laravel/horizon:~1.0"
生成配置
代码语言:javascript复制php artisan vendor:publish --provider="LaravelHorizonHorizonServiceProvider"
接下来输入 http://项目名称/horizon即可进入界面
输入命令监控队列
代码语言:javascript复制php artisan horizon