首页 > 开发 > PHP > 正文

浅谈Laravel队列实现原理解决问题记录

2024-05-04 22:45:59
字体:
来源:转载
供稿:网友

问题

公司项目使用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.phppublic 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);    }  }            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表