关于 Laravel Redis 多个进程同时取队列问题详解

news2025/8/11 21:04:30

最近在工作中遇到了一个问题,开启多个进程处理队列会重复读取 Redis 中队列吗?是否因此导致重复执行任务?下面就来通过示例代码详细介绍下。

使用 Supervisor 监听 Laravel 队列任务,其中 Supervisor 的配置如下:

1

2

3

4

5

6

7

8

[program:laravel-worker]

process_name=%(program_name)s_%(process_num)02d

command=php /var/www/xxx.cn/artisan queue:work --queue=sendfile --tries=3 --daemon

autostart=true

autorestart=true

numprocs=8

redirect_stderr=true

stdout_logfile=/var/www/xxx.cn/worker.log

注意: numprocs = 8,代表开启 8 个进程来执行 command 中的命令。

如下:

1

2

3

4

5

6

7

8

9

10

11

PS C:\Users\tanteng\website\laradock> docker-compose exec php-worker sh

/etc/supervisor/conf.d # ps -ef | grep php

 7 root  0:00 php /var/www/xxx.cn/artisan queue:work --queue=sendfile --tries=3 --daemon

 8 root  0:00 php /var/www/xxx.cn/artisan queue:work --queue=sendfile --tries=3 --daemon

 9 root  0:00 php /var/www/xxx.cn/artisan queue:work --queue=sendfile --tries=3 --daemon

 10 root  0:00 php /var/www/xxx.cn/artisan queue:work --queue=sendfile --tries=3 --daemon

 11 root  0:00 php /var/www/xxx.cn/artisan queue:work --queue=sendfile --tries=3 --daemon

 12 root  0:00 php /var/www/xxx.cn/artisan queue:work --queue=sendfile --tries=3 --daemon

 13 root  0:00 php /var/www/xxx.cn/artisan queue:work --queue=sendfile --tries=3 --daemon

 14 root  0:00 php /var/www/xxx.cn/artisan queue:work --queue=sendfile --tries=3 --daemon

 44 root  0:00 grep php

Laravel 多进程读取队列内容是否会重复

在 Laravel 的某个控制器方法,一次放入多个任务队列:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

public function index(Request $request)

{

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

 $this->dispatch((new SendFile3())->onQueue('sendfile'));

}

在队列处理的方法打印日志,打印处理的队列的 ID:

app/Jobs/SendFile3.php

1

2

3

4

5

6

7

8

public function handle()

{

 info('invoke SendFile3');

 dump('invoke handle');

 $rawbody = $this->job->getRawBody();

 $info = json_decode($rawbody, true);

 info('queue id:' . $info['id']);

}

Laravel 使用 Redis 的 list 作为队列的数据结构,并会为每个队列分配一个 ID,数据结构如下:

1

2

3

4

5

6

7

8

9

{

 "job": "Illuminate\\Queue\\CallQueuedHandler@call",

 "data": {

 "commandName": "App\\Jobs\\SendFile3",

 "command": "O:18:\"App\\Jobs\\SendFile3\":4:{s:6:\"\u0000*\u0000job\";N;s:10:\"connection\";N;s:5:\"queue\";s:8:\"sendfile\";s:5:\"delay\";N;}"

 },

 "id": "hadBcy3IpNsnOofQQdHohsa451OkQs88",

 "attempts": 1

}

请求这个控制器路由(或者命令行方式),就可以看到 Redis 中多了很多队列任务了,如图:

这个时候开启 Supervisor 处理队列任务,并查看日志:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:JaClJzhDEvntzLCRIz6uRQkCVLbE8Y9C

[2017-12-23 19:01:01] local.INFO: queue id:ukHv0Li4P2VgPa55qU6yEOJM27Mo5YwJ

[2017-12-23 19:01:01] local.INFO: queue id:ObMpwDTmnaveBUkU7aan5abt3Agyt90l

[2017-12-23 19:01:01] local.INFO: queue id:fo2qZn2ftSdQtdnKOciMK7iJb4qlhRGE

[2017-12-23 19:01:01] local.INFO: queue id:uLjFMoOU7Wk7bOAd4zpHb3ccRMJHBtR6

[2017-12-23 19:01:01] local.INFO: queue id:87ULqPBObFmGr16nl5wxFVOi71zGCeRM

[2017-12-23 19:01:01] local.INFO: queue id:9UVl0muQLzBqlRI99rChGW2ElXwVEMIE

[2017-12-23 19:01:01] local.INFO: queue id:a0vgyZuz9HtmH7DGHEpXqesFTcQU3QAF

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:2cXuXxopPkgYiV4WO8gv9CJ6CwXeKtYL

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:9acTAYa8cxpJX6Q3Gb1sULokotP8reqZ

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:BPHQvBboChlv4gr2I0vyLVyw9bijtTYJ

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:Fm6tNajdxYKtdQbDMYDmwWJFLnNikRyg

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:nyAbcvSkBVPbaH3e2ItQkoLJlP1ficib

[2017-12-23 19:01:01] local.INFO: queue id:WBHsSVZtP43569UoPXxfLLJcvYmPW7cP

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:bliPnKcRSDApwVmKLNxEhaKelhm0RDEY

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:eOAoQucEIwRz9uZ64xm6IDKgiqj9Xc3W

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:lzise9EiqQqINrhALbmAI4qNg7qylpb2

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:WXYKvcfOhS1pPnwOwUTsenoMv5l5EUXe

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:XtH5JiwLgnrwWzI02Oyi70pihAOkuJUD

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:9ehmE5HImlpNubpY0xWN8UVrOzxeMqws

[2017-12-23 19:01:01] local.INFO: queue id:C1sK87cpZl47edLA0zhfo7PJ9MIEcoyx

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:2kwl51oH4lyyRrljCReGUCkNiJRDl7oe

[2017-12-23 19:01:01] local.INFO: queue id:ObRpoqrYTPYiyv2delMlOXu3sAPpWJlN

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:6qgu6W3TapLjSrt688yv9HRXvDDLxntz

[2017-12-23 19:01:01] local.INFO: queue id:wiTlERhwn7s9cQkfUF9lLlNADpXjKncI

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:ZSLW0VLFBDpL4wjTJzu3Yb3V45pNe807

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:qhZlXLGfGWRluIeNm7VbllmTJZYb2h5n

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:LUx1IByD3L2psNl9BZwHhk2knXyRPzW6

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:M2RESPjyo5hpAFxxL0EQbWwsUq4jpmWn

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:hUsGaiIAOO6ZfGQc5kGHGpsv5RpoRPYO

[2017-12-23 19:01:01] local.INFO: queue id:cEHJsOy6bLeZ4NbncPziaHqlarMeyyEF

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:w4bkFiJKMU5saqG2xKN3ZRL5BYXGATMk

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:0zBuwbxlrEhhxKfYBkVyTY4z35f154sI

[2017-12-23 19:01:01] local.INFO: queue id:mvoZvyDPvq4tcPjEy9G7PMtH3MwPkPik

[2017-12-23 19:01:01] local.INFO: invoke SendFile3

[2017-12-23 19:01:01] local.INFO: queue id:TLvF74eeidECWKtjZqWvW03UJTRPTL9r

[2017-12-23 19:01:01] local.INFO: queue id:me8wyPfgcz0nf9xvcXz0hf2xVxqa1FFS

这 8 个进程并发处理队列,但从打印的日志看,没有出现同样的 ID. 我们再看一下 Laravel 如何使用 Redis 处理队列的。

分析一下 Laravel 队列的处理

Laravel 中入队列方法

1

2

3

4

5

6

public function pushRaw($payload, $queue = null, array $options = [])

{

 $this->getConnection()->rpush($this->getQueue($queue), $payload);

  

 return Arr::get(json_decode($payload, true), 'id');

}

用的是 Redis 的 rpush 命令。

Laravel 中取队列方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public function pop($queue = null)

{

 $original = $queue ?: $this->default;

 $queue = $this->getQueue($queue);

 $this->migrateExpiredJobs($queue.':delayed', $queue);

 if (! is_null($this->expire)) {

  $this->migrateExpiredJobs($queue.':reserved', $queue);

 }

 list($job, $reserved) = $this->getConnection()->eval(

  LuaScripts::pop(), 2, $queue, $queue.':reserved', $this->getTime() + $this->expire

 );

 if ($reserved) {

  return new RedisJob($this->container, $this, $job, $reserved, $original);

 }

}

这里用的是 lua 脚本取队列,如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

public static function pop()

{

 return <<<'LUA'

local job = redis.call('lpop', KEYS[1])

local reserved = false

if(job ~= false) then

reserved = cjson.decode(job)

reserved['attempts'] = reserved['attempts'] + 1

reserved = cjson.encode(reserved)

redis.call('zadd', KEYS[2], ARGV[1], reserved)

end

return {job, reserved}

LUA;

}

那么结论是:从 Laravel 的处理方式和打印的日志结果看,即使多个进程读取同一个队列,也不会读取到一样的数据。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/33695.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

.net----泛型

泛型泛型的基本概念集合类System. Collections. ArrayList泛型集合类System. Collection. Generic. List<T>ArrayListList<T>泛型的定义和类型参数类型参数<T>泛型类和泛型接口泛型类泛型接口泛型结构泛型方法泛型委托和泛型事件default关键字及协变和逆变协…

手动引入jar包,解决Dependency ‘XXX‘ not found的两种方式

目录引言一、使用systemPath导入&#xff08;一&#xff09;将jar包复制到指定文件夹&#xff08;二&#xff09;在pom文件中引入jar包**这里有一个超级大的坑&#xff0c;就是systemPath不支持聚合工程的父子传导&#xff01;&#xff01;&#xff01;****不支持pom工程的继承…

Linux零基础从入门到精通,必学的55个指令合集【上篇】

Linux学习笔记 资料下载&#xff1a; 链接: https://pan.baidu.com/s/1UvwkJaEJO7W3sU5qkCgKzA?pwdfe2f提取码: fe2f 本篇文章主要适用0基础的读者&#xff0c;内容会比较通俗易懂&#xff0c;也会有详细的图解教程&#xff0c;以及运行后的返回结果。我本人在系统性的学习…

G1D22-安装burpsuiteAttacKG

–0724 还有几分钟&#xff0c;把burpsuite安装一下 —0804 hh当然&#xff0c;和室友聊天去啦hhh java目录下找不到jdk&#xff0c;环境变量没法配emm&#xff0c;重新装一下。 emm原来这个文件夹是在安装时自己创建的 啊啊啊&#xff0c;我是猪emm javasuite闪退是因为环境变…

别瞎扯,元宇宙就是没有切实发展?

前言 最近两年&#xff0c;技术圈比较火的话题之一就是&#xff1a;元宇宙&#xff0c;而且2021年被看作是元宇宙元年&#xff0c;直到现在元宇宙话题依然不断&#xff0c;因为元宇宙在过去的一年里太火了。不管是在国内还是国外&#xff0c;元宇宙太火了&#xff0c;而且与元宇…

WPF项目实战布局--通用固件下载 C#

每个作品都是产品 C# WPF版效果&#xff1a; C# winForm版效果: 一.布局设计UI 1.主体&#xff1a;grid 2行 2列 00 下载按钮 20% 01进度条 80% &#xff08;同时显示百分比&#xff09; 10 11都是跨列 显示日志 2.细节&#xff1a;百分比与进度条Value绑定。下载按钮…

java EE初阶 — 计算机工作原理

文章目录1.操作系统2.操作系统的定位3.进程3.1 进程的基本了解3.2 操作系统内核是如何管理软件资源的3.3 PCB里描述了进程的哪些特征3.3.1 三个较为简单的特征3.3.2 进程的调度属性4.内存管理1.操作系统 操作系统是一个搞管理的软件。 对上要给软件提供稳定的运行环境。对下要…

Java面向对象之——继承

文章目录前言一、继承机制二、继承的语法三、父类成员访问&#x1f351;1、子类中访问父类的成员变量&#x1f351;2、子类中访问父类的成员方法四、super关键字五、子类构造方法六、super和this七、继承关系下的代码执行顺序八、访问限定修饰符protected九、Java继承方式十、f…

C#界面里Control.ImeMode 属性的使用

C#界面里Control.ImeMode 属性的使用 Control.ImeMode 属性是获取或设置控件的输入法编辑器 (IME) 模式。 输入法是一种特殊的程序,可以通过某种方式进行激活。 输入法程序总是在别的程序上面,因此它的运行是一种特殊的状态,所以需要特别处理。 因为电脑当时为了输入26个字…

第 46 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(南京),签到题5题

文章目录A.Oops, Its Yesterday Twice MoreM.Windblume FestivalC.Klee in Solitary ConfinementH.CrystalflyD.Paimon Sorting补题链接&#xff1a;https://codeforces.com/gym/103470 A.Oops, It’s Yesterday Twice More Oops, It’s Yesterday Twice More Input file: st…

2020-RKT

2020-RKT&#xff1a;Relation-Aware Self-Attention for Knowledge Tracing 有代码&#xff1a;https://github.com/shalini1194/RKT 摘要 学生在解决练习的过程中获得技能&#xff0c;每一次这样的互动都对学生解决未来练习的能力有明显的影响。 这种影响表现为:1)互动中涉…

Transformer13~目标检测算法汇总

都到了13了 ~~ 还是基于这个的么办法 自从VIT横空出世以来&#xff0c;Transformer在CV界掀起了一场革新&#xff0c;各个上下游任务都得到了长足的进步&#xff0c;然后盘点一下基于Transformer的端到端目标检测算法&#xff01; 原始Tranformer检测器 DETR&#xff08;ECCV…

神经网络架构

神经网络架构 首先我们来看一张图&#xff0c;左边的是生物上的神经网络&#xff0c;右边的是数学版的神经网络 下面我们介绍在深度学习中神经网络的基本架构 整体架构包括层次结构&#xff0c;神经元&#xff0c;全连接&#xff0c;非线性四个部分 我们将针对这四个部分来进…

章节4 Linux操作系统基础知识

4.1-Linux系统结构 Linux系统结构 内核Shell文件系统应用程序 Linux操作系统内核 管理进程管理内存管理驱动管理文件和网络 … Linux Shell 接收用户的命令&#xff0c;经过转换&#xff0c;交给内核去执行 cat —> open() read() 简化操作安全 Linux Shell工具&am…

【docker学习记录】docker安装mysql、redis

目录 docker安装mysql docker安装redis docker安装mysql 1.下载镜像文件 $ sudo docker pull mysql:8.0.31 下载完成后查看一下镜像&#xff1a;sudo docker images 2.创建实例并启动 //mysql版本5 sudo docker run -p 3306:3306 --name mysql \ -v /mydata/mysql/log:/var…

uniapp的安装与基础

解释 由dcloud 公司开发的 多端融合框架 1次开发 多端运行 竞品&#xff1a;apiCloud &#xff0c;appCan &#xff0c;Codova 技术架构 Vue语法小程序的api Hybrid混合开发端 App端 - HTML - nvue&#xff08;原生view&#xff09; - native.js(js原生沟通的桥梁) - weex …

目前是大专学历如何快速提升到本科学历?学历提升有哪几种形式呢?

目前是大专学历如何快速提升到本科学历&#xff1f;学历提升有哪几种形式呢&#xff1f; 如今想要晋升和加薪&#xff0c;很多除了工作能力分级&#xff0c;另一个是文凭&#xff0c;许多企业和机构基本上是基于文凭来决定基本工资&#xff0c;所以想得到更好的待遇&#xff0c…

深度强化学习+金融投资的应用入门

原创文章第114篇&#xff0c;专注“个人成长与财富自由、世界运作的逻辑&#xff0c; AI量化投资”。 今天的核心工作是把强化学习环境整合进我们的AI量化平台中。 网上很多代码都把数据获取和预处理&#xff0c;都整合到强化学习的环境里&#xff0c;对于总体量化平台而言&am…

python搭建沙箱环境

python搭建沙箱环境 文章目录python搭建沙箱环境一&#xff0c;下载virtualenv模块1.1 在线状态的下载1.2 离线状态的下载二&#xff0c;创建沙箱环境&#xff08;虚拟环境&#xff09;三&#xff0c;激活以及退出沙箱环境一&#xff0c;下载virtualenv模块 1.1 在线状态的下载…

JAVA异常

目录JAVA异常1.初识异常2.异常的处理2.1 捕获异常的基本语法2.2 捕获异常2.3 finally的使用2.4 异常的执行流程2.5 抛出异常3.JAVA异常体系4.自定义异常类JAVA异常 1.初识异常 异常指的就是程序在 运行时 出现错误时通知调用者的一种机制. 我们在编写代码的过程中,遇到过许多…