Laravel 隊列組件提供一個統(tǒng)一的 API 集成了許多不同的隊列服務(wù),隊列允許你延后執(zhí)行一個耗時的任務(wù),例如延后至指定的時間才發(fā)送郵件,進而大幅的加快了應(yīng)用程序處理請求的速度。
隊列的配置文件在 config/queue.php
,在這個文件你將可以找到框架中每種不同的隊列服務(wù)的連接設(shè)置,其中包含了 Beanstalkd、IronMQ、Amazon SQS、Redis、null
,以及同步
(本地端使用) 驅(qū)動設(shè)置。驅(qū)動 null
只是簡單的舍棄隊列工作,因此那些工作永遠不會執(zhí)行。
為了能夠使用 database
驅(qū)動,你需要建立一個數(shù)據(jù)表來保存工作。要使用一個遷移建立這個數(shù)據(jù)表,可以執(zhí)行 queue:table
Artisan 命令:
php artisan queue:table
下面的依賴是使用對應(yīng)的隊列驅(qū)動所需的擴展包:
Amazon SQS: aws/aws-sdk-php
Beanstalkd: pda/pheanstalk ~3.0
IronMQ: iron-io/iron_mq ~1.5
Redis: predis/predis ~1.0
應(yīng)用程序中能夠放進隊列的工作都存放在 App\Commands
目錄下,你可以借由下面 Artisan 命令產(chǎn)生一個可使用隊列的命令:
php artisan make:command SendEmail --queued
要推送一個新的工作至隊列,請使用 Queue::push
方法:
Queue::push(new SendEmail($message));
注意: 在這個例子當(dāng)中,我們直接使用
Queue
Facade,然而,常見的作法是借由 Command Bus 去分派隊列命令。我們將會在這篇文章中繼續(xù)使用Queue
Facade,不過,也要熟悉使用 command bus,因為它能夠同時分派你的網(wǎng)站應(yīng)用程序中隊列與同步的命令。
默認情況下,make:command
Artisan 命令會產(chǎn)生一個 "self-handling" 的命令,意味著命令里會包含一個 handle
方法。這個方法將會在隊列執(zhí)行時被調(diào)用。你可以在 handle
方法使用時提示傳入任何你需要的依賴,而 服務(wù)容器 會自動注入他們:
public function handle(UserRepository $users){ //}
如果你希望你的命令有獨立的處理類別,你可以在使用 make:command
命令時加上 --handler
標(biāo)識。
php artisan make:command SendEmail --queued --handler
這個被產(chǎn)生出來的處理類別將會放在 App\Handlers\Commands
目錄下面,并且服務(wù)容器會自動解析。
你也可指定隊列工作送至指定的連接:
Queue::pushOn('emails', new SendEmail($message));
如果你需要發(fā)送一樣的數(shù)據(jù)去幾個不同的隊列工作,你可以使用 Queue::bulk
方法:
Queue::bulk([new SendEmail($message), new AnotherCommand]);
有時候你可能想要延遲執(zhí)行一個隊列工作,舉例來說你希望一個隊列工作在客戶注冊 15 分鐘后才寄送 e-mail,你可以使用 Queue::later
方法來完成這件事情:
$date = Carbon::now()->addMinutes(15);Queue::later($date, new SendEmail($message));
在這個例子中,我們使用 Carbon 日期類庫來指定我們希望隊列工作希望延遲的時間,另外你也可發(fā)送一個整數(shù)來設(shè)置你希望延遲的秒數(shù)。
注意: 在 Amazon SQS 服務(wù)中,有最大 900 秒( 15 分鐘 )的限制。
如果你隊列工作的構(gòu)造器接收一個 Eloquent 模型,只有這個模型的標(biāo)記( identifier ) 會被序列化后放到隊列中。當(dāng)工作真正開始被處理的時候,隊列系統(tǒng)會自動從數(shù)據(jù)庫中重新取得完整的模型實例。這個對你的網(wǎng)站應(yīng)用程序來說是完全透明的,并且 預(yù)防一些在序列化完整 Eloquent 模型實例時可能遇到的問題。
一旦一個工作被處理過后,這個工作必須從隊列中刪除。假如在工作執(zhí)行后沒有發(fā)生錯誤,這個將會自動完成。
如果你希望能夠手動刪除或著釋放工作,在 Illuminate\Queue\InteractsWithQueue
trait 中提供 release
以及 delete
方法的接口。其中 release
方法接受單一一個值:你想要等待工作再次能夠執(zhí)行的秒數(shù)。
public function handle(SendEmail $command){ if (true) { $this->release(30); }}
假如在工作執(zhí)行后發(fā)生錯誤,這個工作將會自動被釋放回到隊列之中,如此一來便能夠再次嘗試執(zhí)行工作。工作會一直被釋放回隊列直到到達應(yīng)用程序的嘗試上限。這個上限數(shù)值可以在使用 queue:listen
或 queue:work
Artisan 命令時候借由 --tries
開關(guān)來設(shè)置。
當(dāng)一個工作執(zhí)行后發(fā)生錯誤,這個工作將會自動的釋放回隊列當(dāng)中,你可以透過 attempts
方法來檢查這個工作已經(jīng)被執(zhí)行的次數(shù):
if ($this->attempts() > 3){ //}
注意: 你的命令處理類別必須使用
Illuminate\Queue\InteractsWithQueue
這個 trait 才能夠使用這個方法。
你也可以推送一個閉包去隊列,這個方法非常的方便及快速的來處理需要使用隊列的簡單的任務(wù):
Queue::push(function($job) use ($id){ Account::delete($id); $job->delete();});
注意: 要讓一個組件變量可以在隊列閉包中可以使用我們會通過
use
命令,試著發(fā)送主鍵及重復(fù)使用的相關(guān)模塊在你的隊列工作中,這可以避免其他的序列化行為。
當(dāng)使用 Iron.io push queues 時,你應(yīng)該在隊列閉包中采取一些其他的預(yù)防措施,我們應(yīng)該在執(zhí)行工作收到隊列數(shù)據(jù)時檢查token是否真來自 Iron.io,舉例來說你推送一個隊列工作到 https://yourapp.com/queue/receive?token=SecretToken
,接下來在你的工作收到隊列的請求時,你就可以檢查token的值是否正確。
Laravel 內(nèi)含一個 Artisan 命令,它將推送到隊列的工作拉來下執(zhí)行,你可以使用 queue:listen
命令,來執(zhí)行這件常駐任務(wù):
php artisan queue:listen
你也可以指定特定隊列連接讓監(jiān)聽器使用:
php artisan queue:listen connection
注意當(dāng)這個任務(wù)開始時,這將會一直持續(xù)執(zhí)行到他被手動停止,你也可以使用一個處理監(jiān)控如 Supervisor 來確保這個隊列監(jiān)聽不會停止執(zhí)行。
你也可以在 listen
命令中使用逗號分隔的隊列連接,來設(shè)置不同隊列連接的優(yōu)先層級:
php artisan queue:listen --queue=high,low
在這個范列中,總是會優(yōu)先處理 high-connection
中的工作,然后才處理 low-connection
。
你也可以設(shè)置給每個工作允許執(zhí)行的秒數(shù):
php artisan queue:listen --timeout=60
此外,你也可以指定讓監(jiān)聽器在拉取新工作時要等待幾秒:
php artisan queue:listen --sleep=5
注意隊列只會在工作時休息,假如有許多可執(zhí)行的工作,隊列會持續(xù)的處理工作而不會休息
當(dāng)你只想處理隊列上的一個工作你可以使用 queue:work
Artisan 命令:
php artisan queue:work
在 queue:work
中也包含了一個 --daemon
選項,強迫隊列處理器持續(xù)處理工作,而不會每次都重新啟動框架,這個作法比起 queue:listen
可有效減少 CPU 使用量,但是卻增加了布署時,對于處理中隊列任務(wù)的復(fù)雜性。
要啟動一個常駐的隊列處理器,使用 --daemon
:
php artisan queue:work connection --daemon php artisan queue:work connection --daemon --sleep=3php artisan queue:work connection --daemon --sleep=3 --tries=3
如你所見 queue:work
命令支持 queue:listen
大多相同的選項參數(shù),你也可使用 php artisan help queue:work
命令來觀看全部可用的選項參數(shù)。
最簡單布署一個應(yīng)用程序使用常駐隊列處理器的方式,就是將應(yīng)用程序在開始布署時轉(zhuǎn)成維護模式,你可以使用 php artisan down
命令來完成這件事情,當(dāng)這個應(yīng)用程序在維護模式,Laravel 將不會允許任何來自隊列上的新工作,但會持續(xù)的處理已存在的工作。
要重新啟動 queue
也是非常容易,請將底下命令加到部署命令:
php artisan queue:restart
上述命令會在執(zhí)行完目前的工作后,重新啟動隊列。
注意: 這個命令依賴緩存系統(tǒng)來排定重新啟動任務(wù)。默認 APCu 無法在命令提示字符中工作。如果你正在使用 APCu 請將
apc.enable_cli=1
加到你的 APCu 設(shè)置當(dāng)中。
常駐隊列處理器不會在處理每一個工作之前都重新啟動框架。因此,你應(yīng)該注意并小心地在工作處理完成之前釋放占用的資源。例如,如果你正在使用 GD 函式庫操作圖片,當(dāng)你完成工作的時候,你應(yīng)該使用 imagedestroy
方法來釋放占用的內(nèi)存。
同樣地,數(shù)據(jù)庫連接可能在長時間執(zhí)行的隊列處理器中斷線,你可以使用 DB::reconnect
方法來確保你每次都有一個全新的連接。
你可以利用強大的 Laravel 5 隊列架構(gòu)來進行推送隊列工作,不需要執(zhí)行任何的常駐或背景監(jiān)聽,目前只支持 Iron.io 驅(qū)動,在你開始前建立一個 Iron.io 帳號及添加你的 Iron 憑證到 config/queue.php
配置文件。
接下來,你可以使用 queue:subscribe
Artisan 命令注冊一個 URL,這將會接收新的推送隊列工作:
php artisan queue:subscribe queue_name queue/receive php artisan queue:subscribe queue_name http://foo.com/queue/receive
現(xiàn)在當(dāng)你登錄你的 Iron 管理后臺,你將會看到你新的推送隊列,以及訂閱的 URL,你可以訂閱許多的 URLs 給你希望的隊列,接下來建立一個 route 給你的 queue/receive
及從 Queue::marshal
方法回傳回應(yīng):
Route::post('queue/receive', function(){ return Queue::marshal();});
這里的 marshal
方法會將觸發(fā)正確的處理類別,而發(fā)送工作到隊列中只要使用一樣的 Queue::push
方法。
事情往往不會如你預(yù)期的一樣,有時候你推送工作到隊列會失敗,別擔(dān)心,Laravel 包含一個簡單的方法去指定一個工作最多可以被執(zhí)行幾次,在工作被執(zhí)行到一定的次數(shù)時,他將會添加至 failed_jobs
數(shù)據(jù)表里,然后失敗工作的數(shù)據(jù)表名稱可以在 config/queue.php
里進行設(shè)置:
要產(chǎn)生一個遷移來建立 failed_jobs
數(shù)據(jù)表,你可以使用 queue:failed-table
Artisan 命令:
php artisan queue:failed-table
你可以指定一個最大值來限制一個工作應(yīng)該最多被執(zhí)行幾次,在你執(zhí)行 queue:listen
時加上 --tries
:
php artisan queue:listen connection-name --tries=3
假如你會想注冊一個事件,這個事件會將會在隊列失敗時被調(diào)用,你可以使用 Queue::failing
方法,這個事件是一個很好的機會讓你可以通知你的團隊通過 e-mail 或 HipChat。
Queue::failing(function($connection, $job, $data){ //});
你可能夠直接在隊列工作類別中定義一個 failed
方法,這讓你能夠在工作失敗時候,執(zhí)行一些特定的動作:
public function failed(){ // 當(dāng)工作失敗的時候會被調(diào)用……}
要看到所有失敗的工作,你可以使用 queue:failed
命令:
php artisan queue:failed
這個 queue:failed
命令將會列出工作 ID、連接、隊列名稱及失敗的時間,可以使用工作 ID 重新執(zhí)行一個失敗的工作,例如一個已經(jīng)失敗的工作的 ID 是 5,我們可以使用下面的命令:
php artisan queue:retry 5
假如你想刪除一個失敗的工作,可以使用 queue:forget
命令:
php artisan queue:forget 5
要刪除全部失敗的工作,可以使用 queue:flush
命令:
php artisan queue:flush
更多建議: