浅谈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 相关文章推荐
第1次亲密接触PHP5(2)
Oct 09 PHP
PHP 执行系统外部命令 system() exec() passthru()
Aug 11 PHP
批量获取memcache值并按key的顺序返回的实现代码
Jun 14 PHP
不支持fsockopen但支持culr环境下下ucenter与modoer通讯问题
Aug 12 PHP
探讨:如何编写PHP扩展
Jun 13 PHP
教你如何使用php session
Oct 28 PHP
php实现监听事件
Nov 06 PHP
详解PHP实现异步调用的4种方法
Mar 14 PHP
[原创]php简单隔行变色功能实现代码
Jul 09 PHP
Laravel4中的Validator验证扩展用法详解
Jul 26 PHP
php 从一个数组中随机的取出若干个不同的数实例
Dec 31 PHP
php使用curl代理实现抓取数据的方法
Feb 03 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
php设计模式 Facade(外观模式)
2011/06/26 PHP
php读取mysql乱码,用set names XXX解决的原理分享
2011/12/29 PHP
浅析Yii中使用RBAC的完全指南(用户角色权限控制)
2013/06/20 PHP
ThinkPHP结合ajax、Mysql实现的客户端通信功能代码示例
2014/06/23 PHP
PHP产生不重复随机数的5个方法总结
2014/11/12 PHP
php模拟post上传图片实现代码
2016/06/24 PHP
PHP类的特性实例分析
2016/09/28 PHP
Linux服务器下PHPMailer发送邮件失败的问题解决
2017/03/04 PHP
jquery弹出关闭遮罩层实例
2013/08/06 Javascript
多次注册事件会导致一个事件被触发多次的解决方法
2013/08/12 Javascript
纯js实现div内图片自适应大小(已测试,兼容火狐)
2014/06/16 Javascript
详解JavaScript中循环控制语句的用法
2015/06/03 Javascript
javascript实现tab切换的两个实例
2015/11/05 Javascript
jQuery Easyui使用(一)之可折叠面板的布局手风琴菜单
2016/08/17 Javascript
浅谈Vue.js
2017/03/02 Javascript
JavaScript 程序错误Cannot use 'in' operator to search的解决方法
2017/07/10 Javascript
underscore之Chaining_动力节点Java学院整理
2017/07/10 Javascript
vue初尝试--项目结构(推荐)
2018/01/30 Javascript
JavaScript对象拷贝与Object.assign用法实例分析
2018/06/20 Javascript
Bootstrap Fileinput 4.4.7文件上传实例详解
2018/07/25 Javascript
对 Vue-Router 进行单元测试的方法
2018/11/05 Javascript
JS基于开关思想实现的数组去重功能【案例】
2019/02/18 Javascript
vue组件之间的数据传递方法详解
2019/04/19 Javascript
vue addRoutes路由动态加载操作
2020/08/04 Javascript
利用React高阶组件实现一个面包屑导航的示例
2020/08/23 Javascript
python列表操作使用示例分享
2014/02/21 Python
python简单猜数游戏实例
2015/07/09 Python
Python计算公交发车时间的完整代码
2020/02/12 Python
Python必须了解的35个关键词
2020/07/16 Python
Python 实现国产SM3加密算法的示例代码
2020/09/21 Python
python利用faker库批量生成测试数据
2020/10/15 Python
python热力图实现简单方法
2021/01/29 Python
挂牌仪式策划方案
2014/05/18 职场文书
我爱幼儿园演讲稿
2014/09/11 职场文书
教师思想工作总结2015
2015/05/13 职场文书
spring cloud gateway中如何读取请求参数
2021/07/15 Java/Android