20分鐘學會Laravel的Queue功能

20分鐘學會Laravel的Queue功能

Laravel 的隊列(Queue)提供了可以跨各種不同隊列驅動的統一 API,例如 File. 關係數據庫. Beanstalkd、Amazon SQS 甚至是 Redis

通過隊列,你可以將一些耗時的任務(Job),比如發送電子郵件的處理往後推延,類似異步的概念。延遲這些耗時的任務可以極大地提升網頁請求響應速度,帶給訪客更好的網頁體驗

隊列設定文件位於 config/queue.php 中。 在這個文件中,你可以找到框架中包含的每個隊列驅動的連接配置,其中包括資料庫,Beanstalkd,Amazon SQS,Redis,和一個同步驅動程序(供本地使用,用處不大)。還包括一個用於丟棄排隊任務的 null 隊列驅動

連接(Connection) Vs. 隊列(Queue)

在開始使用 Laravel 隊列之前,理解「連接」和「隊列」之間的區別非常重要。 在 config/queue.php 配置文件中,有一個 connections 配置選項。 此選項定義到隊列服務(如 Amazon SQS、Beanstalk 或 Redis)的特定連接。 然而,任何給定的隊列連接都可能有多個「隊列」,這些「隊列」可能被認為是不同的堆疊或成堆的排隊任務

請注意, queue 配置文件中的每一組連接配置都包含一個 queue 屬性。 這是將任務發送到指定連接時將被分配到的預設隊列。換句話說,如果你沒有明確指定任務應該被發送到哪個隊列,那麼該任務將被推送到連接配置的 queue 屬性中定義的隊列上:

隊列觀念介紹

關於隊列(Queue)的觀念介紹,Derek Wu寫的相當好,你可以參考他的教學文章,看看他是如何用一家餐廳的運作方式來介紹 Queue,看文章點這裡

快速實作

隊列(Queue)支援的 Driver 很多,本實作是以較為泛用的 database 來進行介紹

務必確認是否把 .env 檔案的 QUEUE_CONNECTION 設定改為 database

Step 1.建立 jobs Migration檔案

輸入以下指令以生成 jobs 表格的 Migration 檔案

php artisan queue:table

Step 2.生成 jobs 表格

輸入以下指令以執行 jobs 表格的 Migration 檔案

php artisan migrate

生成的表格如下圖所示:

Step 3.產生任務(Job)類別

輸入以下指令來生成任務類別,生成類別將位於 app/jobs 裡頭

php artisan make:job 任務名稱

任務(Job)類別大致架構如下,把你的任務(Job)內容寫在 handle() 裡頭:

//app\Jobs\ServerReport.php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Artisan;

class ServerReport implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $timeout = 600;
    protected $time;

    //建構子,用以初始化屬性
    public function __construct($time)
    {
        $this->time = $time;
    }

    //任務處理邏輯
    public function handle()
    {
        if(!$this->time){
            sleep(5);
            Artisan::call('server:report');
        }else{
            sleep($this->time);
            Artisan::call('server:report',['data'=>$this->time]);
        }
    }
}

Step 4.推送任務(Job)到Queue裡頭

你有多個地方可以把任務(Job)送進隊列(Queue),比如控制器方法又或者是直接寫在Route裡頭,以下示範我比較建議的控制器方法

撰寫控制器方法

假設你有一個控制器,名為 SiteController,我們在此建立一個名為 doDispatch 的方法來推送任務

//app\Http\Controllers\SiteController.php

use App\Jobs\ServerReport;

class SiteController extends Controller{
    ...

    //用來推送任務
    public function doDispatch(Request $request , $time)
    {
        $newJob = new ServerReport($time);
        dispatch($newJob);
    }
}
撰寫路由規則

開啟 routes/web.php ,加入以下用於推送任務的路由規則

//routes\web.php

Route::get('/jobs/dispatch/{time}','App\Http\Controllers\SiteController@doDispatch');

Step 5.推送&處理任務

程式碼已經準備的差不多了,現在是時候要讓隊列動起來了,叫起它開始監聽是否有任務要處理了吧

開啟隊列監聽

開啟Terminal,輸入以下指令:

php artisan queue:listen

偵聽相關選項

選項範例 說明
--queue=second 設定要偵聽的隊列,預設為"default",範例為"second"
--timeout=30 設定每個任務允許執行的時間上限,預設為60秒,範例為30秒
--sleep=5 設定隊列開始偵聽後要等多久才開始處理任務,預設為3秒,範例為5秒
--tries=3 隊列處理任務如果錯誤要重試的次數,預設為1秒,範例為3秒
--backoff=3 任務一旦出現未預期的錯誤後要等待的時間,預設為0秒,範例為3秒
--force 強制要求隊列即便在維護模式下也要處理任務
--memory=256 隊列所能使用的記憶體上限,預設為128mb,範例為256mb

如果未開啟隊列監聽,等會推送任務時會先存放在資料庫的 jobs 表格,等到開啟隊列監聽後才進行處理

未開啟監聽,任務暫時存放在 jobs 表格內

如果要離開偵聽模式,在 Terminal 介面按下 Control + C 即可

推送任務

開啟瀏覽器,在應用網域後面加上路徑 '/jobs/dispatch/1' ,完成後試著訪問看看

處理任務

當你看到如下圖出現 processing 表示任務已經開始處理,而 processed 則是代表任務處理結束

進階技巧

將任務推送到指定隊列

假如你的應用不只一個隊列,透過以下的技巧可以把任務推送到指定的對列

建立任務時指定隊列
//app\Http\Controllers\SiteController.php

use App\Jobs\ServerReport;

class SiteController extends Controller{
    ...

    //用來推送任務
    public function doDispatch(Request $request , $time)
    {
        $newJob = (new ServerReport($time))->onQueue('queue_name');
        dispatch($newJob);
    }
}
隊列偵聽時指定名稱

開啟Terminal,輸入以下指令:

php artisan queue:listen --queue=queue_name

建立任務時設定延遲時間

假如你希望任務能夠不要立刻執行,除了延後開啟偵聽,也能夠透過以下的技巧呼叫 delay() 來設定某任務的延遲時間,參數單位為秒

//新任務會延遲30秒才執行
$newJob = (new ServerReport($time))->delay(30);

分享這篇文章:
 

關聯文章:

訂閱電子報,索取 Laravel 學習手冊

價值超過 3000 元,包含常用 Laravel 語法與指令!

一小時免費求職講座

3個應徵軟體工程師前該知道的秘訣

取得免費課程連結

Laravel 百萬年薪特訓營

從最基礎的 PHP 語法開始,包含所有你該知道的網頁基礎知識,連同 Laravel 從零開始一直到實戰,最後還將告訴你如何找好工作,讓你及早擁有百萬年薪