問題
公司專案使用Laravel的開發的兩個專案在同一個測試伺服器部署,公用同一個redis。在使用laravel中的佇列時,產生衝突干擾。
查詢問題原因
在laravel 佇列的操作類Illuminate\Queue\RedisQueue.php
中可以看到pushRaw()
方法:
// 將一任務推入佇列中
public function pushRaw($payload, $queue = null, array $options = [])
{
$this->getConnection()->rpush($this->getQueue($queue), $payload);
return Arr::get(json_decode($payload, true), 'id');
}
從該方法中可以看出Lrarvel佇列的redis實現是通過list結構實現的,rpush(key, value)
是將value推入鍵值為key的redis佇列,key的值則是通過$this->getQueue($queue)
獲取到的
protected function getQueue($queue)
{
return 'queues:'.($queue ?: $this->default);
}
所以的redis中list中的key是 'queues:'.($queue ?: $this->default);
拼接的,$this->default
的值是 RedisQueue
例項化的時候從config\queue.php
配置中載入的 'queue' => 'default'
,$queue
是新增佇列時$this->dispatch( new jobClass()->onQueue($queue) )
傳入的。
// config\queue.php 檔案中的redis配置部分
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => 'default',
'expire' => 60,
],
至此,兩個專案的佇列衝突原因就找到了。因為redis佇列配置中 'queue' => 'default'
都使用的預設的default,所以當共用redis時,預設的佇列list 都是'queue:default',所以導致了衝突。
因為佇列監聽 監聽的佇列名稱是由 --queue引數決定的,如果不傳就是我們上面設定的預設值,若傳了就會根據傳入的佇列名從前往後優先依次處理,具體見程式碼Illuminate\Queue\Worker.php
中:
protected function getNextJob($connection, $queue)
{
if (is_null($queue)) {
return $connection->pop();
}
foreach (explode(',', $queue) as $queue) {
if (! is_null($job = $connection->pop($queue))) {
return $job;
}
}
}
$queue
就是--queue=
傳入的引數,當 $queue不存在是直接呼叫$connection->pop()
當引數存在時會將引數解析,優先處理排在前面的佇列名稱,將佇列名稱傳入pop($queue)
, pop()
會嘗試從指定佇列或預設佇列中獲取佇列任務
// Illuminate\Queue\RedisQueue.php
public function pop($queue = null)
{
$original = $queue ?: $this->default;
$queue = $this->getQueue($queue);
if (! is_null($this->expire)) {
$this->migrateAllExpiredJobs($queue);
}
$job = $this->getConnection()->lpop($queue);
if (! is_null($job)) {
$this->getConnection()->zadd($queue.':reserved', $this->getTime() + $this->expire, $job);
return new RedisJob($this->container, $this, $job, $original);
}
}
至此搞清了佇列執行的原理。
解決方法
將queue的配置檔案中預設佇列修改為不同的名稱,比如: 'queue' => laravel1','queue' => laravel2'。
佇列監聽 php artisan queue:listen redis --queue=laravel1,syncExpress
最後
歡迎關注我的部落格 ^_^
本作品採用《CC 協議》,轉載必須註明作者和本文連結