问题公司项目使用Laravel开发的两个项目部署在同一台测试服务器上,共享同一个redis。在laravel中使用队列时,会出现冲突干扰。找到问题的原因。可以在laravel队列的操作类Illuminate\Queue\RedisQueue.php中看到pushRaw()方法://PushataskintothequeuepublicfunctionpushRaw($payload,$queue=null,array$options=[]){$this->getConnection()->rpush($this->getQueue($queue),$payload);返回Arr::get(json_decode($payload,true),'id');从这个方法中可以看出,Lrarvel队列的redis实现是通过链表结构实现的。rpush(key,value)是将value推入key值为key的redis队列,key的值通过$this->getQueue($queue)得到protectedfunctiongetQueue($queue){return'队列:'.($queue?:$this->default);所以在redis列表中的键是'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时,默认的队列列表是'queue:default',导致冲突。因为队列监听的队列名是由--queue参数决定的,如果不传,就是我们上面设置的默认值,如果传了,则按照传入的队列名进行处理从前到后,具体见代码Illuminate\InQueue\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不存在时,直接调用,将队列名传入pop($queue),pop()会尝试从指定队列或默认队列中获取队列Task//Illuminate\Queue\RedisQueue.phppublicfunctionpop($queue=null){$original=$queue?:$this->default;$queue=$this->getQueue($queue);如果(!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);返回新的RedisJob($this->container,$this,$job,$original);}}至此,我们就想通了队列的执行原理解决方案将队列配置文件中的默认队列改成不同的名称,例如:'queue'=>laravel1','queue'=>laravel2'。队列监控phpartisanqueue:listenredis--queue=laravel1,syncExpress终于遇到问题了,别急着求医。从代码入手,分析理解实现原理,找准点,解决方法可能很简单,^_^。欢迎关注我的博客
