浅谈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 相关文章推荐
discuz authcode 经典php加密解密函数解析
Jul 12 PHP
解析用PHP读写音频文件信息的详解(支持WMA和MP3)
May 10 PHP
PHP生成验证码时“图像因其本身有错无法显示”的解决方法
Aug 07 PHP
PHP+jQuery翻板抽奖功能实现
Oct 19 PHP
PHP结合jQuery插件ajaxFileUpload实现异步上传文件实例
Aug 17 PHP
PHP Try-catch 语句使用技巧
Feb 28 PHP
PHP的Yii框架中使用数据库的配置和SQL操作实例教程
Mar 17 PHP
PHP目录操作实例总结
Sep 27 PHP
Laravel中基于Artisan View扩展包创建及删除应用视图文件的方法
Oct 08 PHP
PHP实现登陆并抓取微信列表中最新一组微信消息的方法
Jul 10 PHP
thinkPHP框架实现的无限回复评论功能示例
Jun 09 PHP
php常用字符串查找函数strstr()与strpos()实例分析
Jun 21 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
2006/12/14 PHP
php array的学习笔记
2012/05/10 PHP
Yii2框架引用bootstrap中日期插件yii2-date-picker的方法
2016/01/09 PHP
thinkPHP模板中for循环与switch语句用法示例
2016/11/30 PHP
php web环境和命令行环境下查找php.ini的位置
2019/07/17 PHP
jquery ready函数源代码研究
2009/12/06 Javascript
jQuery Dialog 弹出层对话框插件
2010/08/09 Javascript
js读取本地excel文档数据的代码
2010/11/11 Javascript
JSON.stringify转换JSON时日期时间不准确的解决方法
2014/08/08 Javascript
从数据库读取数据后将其输出成html标签的三种方法
2014/10/13 Javascript
jQuery的图片滑块焦点图插件整理推荐
2014/12/07 Javascript
再分享70+免费的jquery 图片滑块效果插件和教程
2014/12/15 Javascript
15款jQuery分布引导插件分享
2015/02/04 Javascript
原生JS封装ajax 传json,str,excel文件上传提交表单(推荐)
2016/06/21 Javascript
详解node.js平台下Express的session与cookie模块包的配置
2017/04/26 Javascript
iscroll实现下拉刷新功能
2017/07/18 Javascript
AngularJS通过ng-Img-Crop实现头像截取的示例
2017/08/17 Javascript
JS实现动态生成html table表格的方法分析
2018/07/11 Javascript
深入理解使用Vue实现Context-Menu的思考与总结
2019/03/09 Javascript
vue无限轮播插件代码实例
2019/05/10 Javascript
原生js实现商品筛选功能
2019/10/28 Javascript
JavaScript设计模式之策略模式实现原理详解
2020/05/29 Javascript
[02:42]决战东方!DOTA2亚洲邀请赛重启荣耀之争
2017/03/17 DOTA
pycharm+django创建一个搜索网页实例代码
2018/01/24 Python
Django 跨域请求处理的示例代码
2018/05/02 Python
Python中关键字global和nonlocal的区别详解
2018/09/03 Python
python对日志进行处理的实例代码
2018/10/06 Python
pymysql 开启调试模式的实现
2019/09/24 Python
Python基于requests库爬取网站信息
2020/03/02 Python
Nordgreen台湾官网:极简北欧设计手表
2019/08/21 全球购物
学期自我评价
2014/01/27 职场文书
四年级科学教学反思
2014/02/10 职场文书
任命书格式
2014/06/05 职场文书
中学教师师德师风承诺书
2015/04/28 职场文书
学校捐款活动总结
2015/05/09 职场文书
Python开发工具Pycharm的安装以及使用步骤总结
2021/06/24 Python