消息隊列的主要特點是異步處理,主要目的是減少請求響應時間和解耦。所以主要的使用場景就是將比較耗時而且不需要即時(同步)返回結果的操作作爲消息放入消息隊列。同時由於使用了消息隊列,只要保證消息格式不變,消息的發送方和接收方並不需要彼此聯繫,也不需要受對方的影響,即解耦和。
配置隊列
安裝擴展包
composer require "predis/predis:~1.0"
隊列的配置信息存放在config/queue.php
在.env中修改配置驅動
QUEUE_DRIVER=redis
使用redis驅動
REDIS_CLIENT=predis
使用predis
生成隊列需要的數據表
有時候隊列會執行失敗,這張表用於存放失敗信息
php artisan queue:failed-table
php artisan migrate
生成任務類
生成的文件存放在 app\Jobs
php artisan make:jon QueueName
該文件有兩個方法
_construct
構造方法 注入模型
handler
任務的邏輯
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Models\Topic;
use App\Handlers\TranslateHandler;
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(\App\Handlers\TranslateHandler::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.通過命令監控
php artisan queue:listen
2.有圖形界面的監控
Horizon
安裝Horizon
composer require "laravel/horizon:~1.0"
生成配置
php artisan vendor:publish --provider="Laravel\Horizon\HorizonServiceProvider"
接下來輸入 http://項目名稱/horizon即可進入界面
輸入命令監控隊列
php artisan horizon