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);