浅谈Laravel队列实现原理解决问题记录
问题
公司项目使用Laravel的开发的两个项目在同一个测试服务器部署,公用同一个redis。在使用laravel中的队列时,产生冲突干扰。
查找问题原因
在laravel队列的操作类Illuminate\Queue\RedisQueue.php中可以看到pushRaw()方法:
//将一任务推入队列中 publicfunctionpushRaw($payload,$queue=null,array$options=[]) { $this->getConnection()->rpush($this->getQueue($queue),$payload); returnArr::get(json_decode($payload,true),'id'); }
从该方法中可以看出Lrarvel队列的redis实现是通过list结构实现的,rpush(key,value)是将value推入键值为key的redis队列,key的值则是通过$this->getQueue($queue)获取到的
protectedfunctiongetQueue($queue) { return'queues:'.($queue?:$this->default); }
所以的redis中list中的key是'queues:'.($queue?:$this->default);拼接的,$this->default的值是RedisQueue实例化的时候从config\queue.php配置中加载的'queue'=>'default',$queue是添加队列时$this->dispatch(newjobClass()->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中:
protectedfunctiongetNextJob($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 publicfunctionpop($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); returnnewRedisJob($this->container,$this,$job,$original); } }
至此搞清了队列执行的原理。
解决方法
将queue的配置文件中默认队列修改为不同的名称,比如:'queue'=>laravel1','queue'=>laravel2'。
队列监听phpartisanqueue:listenredis--queue=laravel1,syncExpress
最后
遇到问题,莫要病急乱投医。从代码入手,分析理解实现原理,找对点,解决方法也许很简单,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。