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


Posted in PHP onAugust 19, 2017

问题

公司项目使用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

最后

遇到问题,莫要病急乱投医。从代码入手,分析理解实现原理,找对点,解决方法也许很简单,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
PHP容易忘记的知识点分享
Apr 30 PHP
浅析PHP绘图技术
Jul 03 PHP
ThinkPHP中的关联模型注意点
Jun 16 PHP
php中file_get_contents与curl性能比较分析
Nov 08 PHP
PHP中返回引用类型的方法
Apr 03 PHP
PHP性能分析工具XHProf安装使用教程
May 13 PHP
PHP的关于变量和日期处理的一些面试题目整理
Aug 10 PHP
php事件驱动化设计详解
Nov 10 PHP
PHP基于DOM创建xml文档的方法示例
Feb 08 PHP
PHP实现Huffman编码/解码的示例代码
Apr 20 PHP
PHP面向对象程序设计继承用法简单示例
Dec 28 PHP
php实现的生成排列算法示例
Jul 25 PHP
yii2 commands模式以及配置crontab定时任务的方法
Aug 19 #PHP
利用 fsockopen() 函数开放端口扫描器的实例
Aug 19 #PHP
PHPMailer使用QQ邮箱实现邮件发送功能
Aug 18 #PHP
PHP实现自动发送邮件功能代码(qq 邮箱)
Aug 18 #PHP
详解PHP如何更好的利用PHPstorm的自动提示
Aug 18 #PHP
Laravel学习教程之本地化模块
Aug 18 #PHP
PDO操作MySQL的基础教程(推荐)
Aug 18 #PHP
You might like
ThinkPHP使用心得分享-上传类UploadFile的使用
2014/05/15 PHP
PHP仿微信发红包领红包效果
2016/10/30 PHP
jquery 模拟类搜索框自动完成搜索提示功能(改进)
2010/05/24 Javascript
jquery 无限级联菜单案例分享
2013/03/26 Javascript
在JavaScript中实现类的方式探讨
2013/08/28 Javascript
jQuery下拉美化搜索表单效果代码分享
2015/08/25 Javascript
Bootstrap CSS组件之按钮下拉菜单
2016/12/17 Javascript
移动端点击态处理的三种实现方式
2017/01/12 Javascript
原生JS仿QQ阅读点击展开、收起效果
2017/03/08 Javascript
Bootstrap实现的经典栅格布局效果实例【附demo源码】
2017/03/30 Javascript
JS简单实现获取元素的封装操作示例
2017/04/07 Javascript
angularJs使用$watch和$filter过滤器制作搜索筛选实例
2017/06/01 Javascript
Angular使用 ng-img-max 调整浏览器中的图片的示例代码
2017/08/17 Javascript
简单实现js进度条加载效果
2020/03/25 Javascript
关于meta viewport中target-densitydpi属性详解(推荐)
2017/08/18 Javascript
vue计算属性时v-for处理数组时遇到的一个bug问题
2018/01/21 Javascript
JavaScript的数据类型转换原则(干货)
2018/03/15 Javascript
vue引入axios同源跨域问题
2018/09/27 Javascript
js简单的分页器插件代码实例
2019/09/11 Javascript
Vue3 中的数据侦测的实现
2019/10/09 Javascript
vue项目从node8.x升级到12.x后的问题解决
2019/10/25 Javascript
Vue 中使用lodash对事件进行防抖和节流操作
2020/07/26 Javascript
js绘制一条直线并旋转45度
2020/08/21 Javascript
Python  __getattr__与__setattr__使用方法
2008/09/06 Python
使用相同的Apache实例来运行Django和Media文件
2015/07/22 Python
Python随手笔记之标准类型内建函数
2015/12/02 Python
python高手之路python处理excel文件(方法汇总)
2016/01/07 Python
Python tkinter 下拉日历控件代码
2020/03/04 Python
python GUI库图形界面开发之PyQt5 MDI(多文档窗口)QMidArea详细使用方法与实例
2020/03/05 Python
python GUI库图形界面开发之PyQt5信号与槽事件处理机制详细介绍与实例解析
2020/03/08 Python
python 在sql语句中使用%s,%d,%f说明
2020/06/06 Python
python编写softmax函数、交叉熵函数实例
2020/06/11 Python
python 使用paramiko模块进行封装,远程操作linux主机的示例代码
2020/12/03 Python
交通运输局四风问题对照检查材料思想汇报
2014/10/09 职场文书
MySQL图形化管理工具Navicat安装步骤
2021/12/04 MySQL
Windows server 2003卸载和安装IIS的图文教程
2022/07/15 Servers