以laravel5.5為例子:
1.配置隊列:composer require "predis/predis:~1.0"
a.在ENV中配置:QUEUE_DRIVER=redis
b.配置表,失敗時隊列的失敗信息內容會存到此表里。命令:php artisan queue:failed-table
c.生成記錄失敗的數據表:php aritsan migrate
2.生成一個任務類出來:php artisan make:job TranslateSlug
<?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\SlugTranslateHandler; 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(SlugTranslateHandler::class)->translate($this->topic->title); // 為了避免模型監控器死循環調用,我們使用 DB 類直接對數據庫進行操作 \DB::table('topics')->where('id', $this->topic->id)->update(['slug' => $slug]); } }
該類實現了 Illuminate\Contracts\Queue\ShouldQueue
接口,該接口表明 Laravel 應該將該任務添加到后台的任務隊列中,而不是同步執行。
引入了 SerializesModels
trait,Eloquent 模型會被優雅的序列化和反序列化。隊列任務構造器中接收了 Eloquent 模型,將會只序列化模型的 ID。這樣子在任務執行時,隊列系統會從數據庫中自動的根據 ID 檢索出模型實例。這樣可以避免序列化完整的模型可能在隊列中出現的問題。
handle
方法會在隊列任務執行時被調用。值得注意的是,我們可以在任務的 handle
方法中可以使用類型提示來進行依賴的注入。Laravel 的服務容器會自動的將這些依賴注入進去,與控制器方法類似。
還有一點需要注意,我們將會在模型監控器中分發任務,任務中要避免使用 Eloquent 模型接口調用,如:create()
, update()
, save()
等操作。否則會陷入調用死循環 —— 模型監控器分發任務,任務觸發模型監控器,模型監控器再次分發任務,任務再次觸發模型監控器.... 死循環。在這種情況下,使用 DB
類直接對數據庫進行操作即可。
3.任務分發:
<?php namespace App\Observers; use App\Models\Topic; use App\Jobs\TranslateSlug; // creating, created, updating, updated, saving, // saved, deleting, deleted, restoring, restored class TopicObserver { public function saving(Topic $topic) { // XSS 過濾 $topic->body = clean($topic->body, 'user_topic_body'); // 生成話題摘錄 $topic->excerpt = make_excerpt($topic->body); // 如 slug 字段無內容,即使用翻譯器對 title 進行翻譯 if ( ! $topic->slug) { // 推送任務到隊列 dispatch(new TranslateSlug($topic)); } } }
4.開始測試,監聽 php artisan queue:listen