资讯专栏INFORMATION COLUMN

分析Laravel队列实现原理解决问题记录

Corwien / 2563人阅读

摘要:在使用中的队列时,产生冲突干扰。文件中的配置部分至此,两个项目的队列冲突原因就找到了。队列监听最后遇到问题,莫要病急乱投医。从代码入手,分析理解实现原理,找对点,解决方法也许很简单,。

问题

公司项目使用Laravel的开发的两个项目在同一个测试服务器部署,公用同一个redis。在使用laravel中的队列时,产生冲突干扰。

查找问题原因

在laravel 队列的操作类 IlluminateQueueRedisQueue.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 实例化的时候从 configqueue.php 配置中加载的 "queue" => "default" $queue 是添加队列时$this->dispatch( new jobClass()->onQueue($queue) )传入的。

// configqueue.php 文件中的redis配置部分
"redis" => [
            "driver"     => "redis",
            "connection" => "default",
            "queue"      => "default",
            "expire"     => 60,
        ],

至此,两个项目的队列冲突原因就找到了。因为redis队列配置中 "queue" => "default" 都使用的默认的default,所以当共用redis时,默认的队列list 都是"queue:default",所以导致了冲突。

因为队列监听 监听的队列名称是由 --queue参数决定的,如果不传就是我们上面设置的默认值,若传了就会根据传入的队列名从前往后优先依次处理,具体见代码IlluminateQueueWorker.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()会尝试从指定队列或默认队列中获取队列任务

// IlluminateQueueRedisQueue.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

最后

遇到问题,莫要病急乱投医。从代码入手,分析理解实现原理,找对点,解决方法也许很简单,^_^。

欢迎关注我的博客

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/25700.html

相关文章

  • 个人整理, 阅读过的好文章 (每天随时更新)

    摘要:大家有好的文章可以在评论下面分享出来共同进步本文链接数组使用之道程序员进阶学习书籍参考指南教你在不使用框架的情况下也能写出现代化代码巧用数组函数框架中间件实现没错,这就是面向对象编程设计模式需要遵循的个基本原则令人困惑的在中使用协程实现多任 大家有好的文章,可以在评论下面分享出来, 共同进步! 本文github链接 php PHP 数组使用之道 PHP程序员进阶学习书籍参考指南 教你...

    Chiclaim 评论0 收藏0
  • Laravel核心解读 -- 事件系统

    摘要:对于包含通配符的事件名,会被统一放入数组中,是用来创建事件对应的的如果是监听器是类,去创建监听类创建的时候,会判断监听对象是监听类还是闭包函数。对于闭包监听来说,会再包装一层返回一个闭包函数作为事件的监听者。 事件系统 Laravel 的事件提供了一个简单的观察者实现,能够订阅和监听应用中发生的各种事件。事件机制是一种很好的应用解耦方式,因为一个事件可以拥有多个互不依赖的监听器。lar...

    chengjianhua 评论0 收藏0
  • 献给虚拟主机 Laravel 4 用户: 全功能 MySQL 队列驱动器 L4mysqlqueue

    摘要:几小时前刚刚发布的为队列功能提供了官方原生的驱动器,完全取代了本软件包的功能。不过这也并不意味着就是虚拟主机没戏,必须云主机起跳的小网站杀手。性能确实低下受制于,绝对禁止用于大数量高密度任务的场合。虚拟主机肯定不会提供。 几小时前刚刚发布的 Larevel 5.0 为队列功能提供了官方原生的database驱动器,完全取代了本软件包的功能。 对于Laravel 5及以上版本,本文的内...

    missonce 评论0 收藏0
  • Laravel5.2队列驱动expire参数设置带来的重复执行问题 数据库驱动

    摘要:已经取消了参数,都用来执行。取数据的过程事物处理已经打开。取得符合条件的队列后程序会更新该条数据,并且更新完后即。 connections => [ .... database => [ driver => database, table => jobs, queue => defaul...

    ysl_unh 评论0 收藏0
  • 一个 16年毕业生所经历的 PHP 面试

    摘要:正确做法是给加索引,还有联合索引,并不能避免全表扫描。 前言:有收获的话请加颗小星星,没有收获的话可以 反对 没有帮助 举报三连 有心的同学应该会看到我这个noteBook下面的其它知识,希望对你们有些许帮助。 本文地址 时间点:2017-11 一个16年毕业生所经历的php面试 一、什么是面试 二、面试准备 1. 问:什么时候开始准备? 2. 问:怎么准备? 三、面试...

    dabai 评论0 收藏0

发表评论

0条评论

Corwien

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<