1 環境
Laravel是一種類似ThinkPHP的php框架,封裝的諸多功能可以很方便的使用。隊列Queue便是其中之一。
Windows環境下,可使用PHPstorm作爲Laravel的集成開發環境IDE。
2 隊列
Laravel可配置多種隊列驅動,包括 "sync", "database", "beanstalkd", "sqs", "redis", "null"(具體參見app/config/queue.php)
其中sync爲同步,database爲使用數據庫,後面三種爲第三方隊列服務,最後一種爲不使用隊列。
通過在 .env 中的 QUEUE_CONNECTION 選項,來決定選擇何種驅動。
如 QUEUE_CONNECTION=database 即爲選擇數據庫驅動隊列。
3 原理
所謂隊列,會有數據的生產者和消費者之分。生產者向隊列中投遞數據,消費者從隊列中獲取數據。
比如向用戶發送郵件的場景:現在有10w封郵件需要發送,最簡單的,我們需要有一個方法將郵件的收件人、內容等,拆分成10w條任務放在隊列中,同時需要設置一個回調方法負責處理每條任務。當隊列中有郵件發送任務時,隊列會主動調用回調方法,並傳遞任務詳情進去。回調方法處理完成後,單條郵件即發送完畢。其他郵件依樣處理。
4 使用數據庫驅動隊列
4.1 生成任務表
在終端下輸入
php artisan queue:table
php artisan migrate
在數據庫連接正常的情況下,會在數據庫中出現jobs表:
[id] bigint
[queue] nvarchar(255)
[payload] nvarchar(max)
[attempts] tinyint
[reserved_at] int
[available_at] int
[created_at] int
4.2 創建任務類
php artisan make:job SendEmail
在終端內執行上述命令,會自動生成 app/Jobs/SendMail.php 文件
class SendMail implements ShouldQueue
在該文件的handle方法中,可以放置任務處理邏輯。
4.3 發送任務
在任意位置,均可像下面一樣調用 dispatch 發送任務
SendMail::dispatch($email);
4.4 驅動隊列
完成上述步驟後,可以在數據庫中發現一條記錄(導出爲insert SQL語句):
INSERT INTO [jobs]([id], [queue], [payload], [attempts], [reserved_at], [available_at], [created_at]) VALUES (6, N'default', N'{"displayName":"App\\Jobs\\ProcessPodcast","job":"Illuminate\\Queue\\CallQueuedHandler@call","maxTries":null,"timeout":null,"timeoutAt":null,"data":{"commandName":"App\\Jobs\\ProcessPodcast","command":"O:23:\"App\\Jobs\\ProcessPodcast\":8:{s:29:\"\u0000App\\Jobs\\ProcessPodcast\u0000data\";s:6:\"111222\";s:6:\"\u0000*\u0000job\";N;s:10:\"connection\";N;s:5:\"queue\";N;s:15:\"chainConnection\";N;s:10:\"chainQueue\";N;s:5:\"delay\";N;s:7:\"chained\";a:0:{}}"}}', 0, NULL, 1545980176, 1545980176);
此時任務已經放置在數據庫內,只有將隊列運行起來後,隊列才能主動調用回調方法。
php artisan queue:work
在終端內運行上述命令即可。該命令還有諸多參數,如deamon、tries等,可根據需要指定。
4.5 守護進程
爲了保證應用服務的穩定性,需要開啓守護進程。
Linux下,一般使用 Supervisor ,Windows下使用 Forever,可參考 這裏.
4.6 執行失敗的處理
對於處理失敗的任務,Laravel也提供的解決方案。通過運行如下命令,即可創建表以記錄失敗任務。
php artisan queue:failed-table
php artisan migrate
在數據庫中即生成 failed_jobs :
[id] bigint
[connection] nvarchar(max)
[queue] nvarchar(max)
[payload] nvarchar(max)
[exception] nvarchar(max)
[failed_at] datetime
導致任務失敗的 Exception 會被傳遞到 SendMail 的 failed 方法,因而你需要在SendMail中自行實現該方法,並做進一步處理。
任務執行失敗的原因有很多,如傳參錯誤、嘗試次數超過限制、超時、甚至在 handle 方法中拋出異常,均會作爲失敗任務處理。
4.7 任務執行前後的處理
Laravel提供了任務執行前後的處理入口,即在 App/Providers/AppServiceProvider 中的 boot() 中加入如下代碼:
public function boot()
{
Queue::before( function (JobProcessing $event) {
Log::info("處理任務前");
});
Queue::after( function (JobProcessed $event) {
Log::info("處理任務後");
});
}
傳遞的 $event 中,帶有任務詳情,幾個簡單的例子:
$event->connectionName
$event->job
$event->job->payload()
5 使用 Redis 驅動隊列
5.1 Laravel 安裝 Predis 包
在 Laravel 中使用 Redis 之前,需要通過 Composer 安裝 predis/predis 包:
composer require predis/predis
上述拓展是幫助Laravel與Redis打交道的,我們現在還缺少Redis服務。
如果此時將 .env 中的 QUEUE_CONNECTION 改爲 redis,訪問時會報錯:
Predis \ Connection \ ConnectionException (10061)
����Ŀ����������ܾ��������ӡ� [tcp://127.0.0.1:6379]
5.2 配置 Redis 服務
在 Redis官網 下載源碼後自行編譯即可。
官方並未提供Windows版,Redis的Windows版式由微軟工作組維護的,你可以從其 GitHub頁 找到。不過貌似已經不再維護了,最新的版本是16年發佈的3.2.100。
Linux下通過簡單的運行
./redis-server
即可開啓服務,再通過
./redis-cli
來嘗試使用Redis。使用也很簡單,就是 set key value 和 get key。
Windows下安裝後,在命令行中 cd 到安裝目錄
C:\Program Files\Redis>redis-server redis.windows.conf
C:\Program Files\Redis>netstat -an|find "6379"
TCP 127.0.0.1:6379 0.0.0.0:0 LISTENING
即可開啓Redis服務。
Redis服務的停止是通過如下命令:
C:\Program Files\Redis>redis-server --service-stop