隊(duì)列常常用于兩種場景,一種是高并發(fā)的情況,一種是耗時(shí)的操作,可以將任務(wù)放到隊(duì)列中去,消費(fèi)者從隊(duì)列取任務(wù)執(zhí)行,當(dāng)然還有失敗的情況如何處理,以及延遲,重試,更復(fù)雜的情況還有優(yōu)先級的實(shí)現(xiàn)。
在Laravel 5中使用隊(duì)列非常簡單,并且失敗處理,延遲,重試的方法都已經(jīng)實(shí)現(xiàn),下面簡單嘗試了一下Laravel的隊(duì)列服務(wù)。
Laravel默認(rèn)支持以下幾種隊(duì)列服務(wù):sync, database, beanstalkd, sqs, redis,本例使用redis作為隊(duì)列服務(wù),需先配置好Redis服務(wù)。
1.隊(duì)列服務(wù)配置
在配置文件queue.php的connections中已經(jīng)默認(rèn)定義了redis的連接:
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => 'default',
'expire' => 60,
],
在.env環(huán)境配置文件中把默認(rèn)的隊(duì)列驅(qū)動(dòng)改成redis:
QUEUE_DRIVER=redis
為了避免配置緩存的影響,執(zhí)行以下命令清除并重建配置緩存:
php artisan config:cache
2.新建Queueable Jobs
使用命令:
php artisan make:job MyJob
新建一個(gè)名為MyJob的隊(duì)列處理類,在App/Jobs目錄下自動(dòng)生成一個(gè)MyJob.php文件。
MyJob.php需要實(shí)現(xiàn)handle方法,用來具體執(zhí)行隊(duì)列任務(wù),構(gòu)造函數(shù)可以用來傳遞需要的參數(shù),handle方法支持依賴注入。
這里handle方法隨便寫了一個(gè),就是往一個(gè)list類型數(shù)據(jù)結(jié)構(gòu)中存一個(gè)key-value數(shù)據(jù),測試消費(fèi)隊(duì)列的時(shí)候有沒有起作用,構(gòu)造函數(shù)傳兩個(gè)參數(shù)就是key和value.
<?php
namespace App\Jobs;
use App\Jobs\Job;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Redis;
class MyJob extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
private $key;
private $value;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($key, $value)
{
$this->key = $key;
$this->value = $value;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
Redis::hset('queue.test', $this->key, $this->value);
}
public function failed()
{
dump('failed');
}
}
在控制器中使用dispatch方法調(diào)用隊(duì)列,將任務(wù)放入隊(duì)列中,控制器中寫個(gè)方法如public function test(),new MyJob的構(gòu)造函數(shù)傳兩個(gè)隨機(jī)生成的字符串參數(shù):
$job = new MyJob('key_'.str_random(4), str_random(10));
$queueId = dispatch($job);
dd($queueId);
配置并訪問路由,可以多訪問幾次,然后到Redis中查看,會(huì)發(fā)現(xiàn)把隊(duì)列存入了一個(gè)queue::queue:default的List結(jié)構(gòu)中:
其中value內(nèi)容如下,這是轉(zhuǎn)換成json格式的,而實(shí)際上是經(jīng)過序列號的字符串:
{
"job": "Illuminate\\Queue\\CallQueuedHandler@call",
"data": {
"command": "O:14:\"App\\Jobs\\MyJob\":6:{s:19:\"\u0000App\\Jobs\\MyJob\u0000key\";i:1;s:21:\"\u0000App\\Jobs\\MyJob\u0000value\";i:2;s:10:\"connection\";N;s:5:\"queue\";N;s:5:\"delay\";N;s:6:\"\u0000*\u0000job\";N;}"
},
"id": "EV2bhqUlx0T8pRCVHw1qT0fkP8AQcyI8",
"attempts": 1
}
這里data參數(shù)里包含了隊(duì)列服務(wù)Job的名稱,構(gòu)造函數(shù)的參數(shù)等信息,消費(fèi)者執(zhí)行任務(wù)的依據(jù)。attempts表示重試的次數(shù),往往執(zhí)行隊(duì)列任務(wù)失敗了會(huì)重試,可以設(shè)置最多嘗試次數(shù)。
通過 --tries 參數(shù)項(xiàng)來設(shè)置隊(duì)列任務(wù)允許的最大嘗試次數(shù):
php artisan queue:work redis --tries=3
3.消費(fèi)隊(duì)列
這個(gè)時(shí)候任務(wù)只是入了隊(duì)列,但并沒有消費(fèi),執(zhí)行:
php artisan queue:listen
這個(gè)命令,Laravel就開始消費(fèi)隊(duì)列。
可以看到這幾個(gè)任務(wù)以此被消費(fèi),再去Redis看看有沒有實(shí)現(xiàn)預(yù)期要達(dá)到的效果,每個(gè)任務(wù)往queue.test插入一個(gè)hash類型的結(jié)構(gòu)。