深入了解laravel消费队列的两种工作模式

由来

一直在用laravel的Queue, 并且最近使用中也遇到一些问题,急迫的想搞清楚Laravel中的Queue到底是如何跑起来的 大家都知道Queue的运行有两种模式,一种是Wok, 一种是Listen, 在看过的博客中讲到的都不是很深入,大部分都是重复的Copy, 没有特别详细的讲解,知其然,而不知所以然,对于喜欢为Why的Coder来说很痛苦,于是就有了这篇文章,希望对您能有帮助

辅助工具

  1. xhprof, xhgui
  2. socketLog

宏观上分模块理解Queue消费的工作过程

下面我将一个完整的消费过程分为以下步骤理解,以及详细的陪图说明

  1. 命令行初始化模块
  2. 消费队列命令运行模块
  3. 任务的存储与操作
  4. 唤起执行任务的模块
  5. 具体任务执行模块

下面是一张UML图像,我把上面的5个模块中用到的重要的类都画了下来

在线浏览地址 点击链接

下面是一张类函数调用堆栈图,时序图太长画出来也不大好看

深入了解laravel消费队列的两种工作模式_第1张图片

微观理解Listener VS Worker的区别

几种运行模式

  1. queue:work || queue:work --once 默认只执行一次队列请求, 当请求执行完成后就终止;
  2. queue:listen 监听队列请求, 只要运行着, 就能一直接受请求, 除非手动终止;
  3. queue:work --daemon 同 listen 一样, 只要运行着, 就能一直接受请求, 不一样的地方是在这个运行模式下, 当新的请求到来的时候, 不重新加载整个框架, 而是直接 fire 动作, 当更新代码的时候, 需要停止, 然后重新启动, 这样修改的代码才能起作用

Laravel5.3之前和之后对Worker的timeout有改动,>=5.3的version Work模式也支持了超时检测

相同点

  1. 最终都是执行的work
    <5.3 -> queue:work %s --queue=%s --delay=%s --memory=%s --sleep=%s --tries=%s
    >=5.3 -> queue:work %s --once --queue=%s --delay=%s --memory=%s --sleep=%s --tries=%s

下面的图片中可以看到, work只是执行了一次WorkCommand,然后循环处理每个任务, listen是用ListenCommand作为一个入口或者叫包装器,实际里面真正执行的还是work once

work

  • 深入了解laravel消费队列的两种工作模式_第2张图片

listen

  • 深入了解laravel消费队列的两种工作模式_第3张图片

不同点

  1. Listen 方式使用的是Process实例去循环的执行Work Once, 所以你修改的Job代码会被从新加载,因为Listen的消费是单独开启独立的进程去消费的,当然浪费性能有进程开销
  2. Work 方式是while(true), 在当前的进程中去处理任务, 修改的代码不会生效
  3. Work的超时机制,在Laravel<=5.2前Work是不支持超时参数的,在Laravel>=5.3起,Work的daemon模式也开始支持超时机制了,这种机制使用的时钟 pcntl_alarm机制,时间到达后出发信号执行kill进程的操作,这种模式开启的要求是 version_compare(PHP_VERSION, '7.1.0') >= 0 && extension_loaded('pcntl')
  4. Listen的超时机制, 只要进程运行着就会自动检测
function wait(){
    ...
    do {
        $this->checkTimeout();
        ...
    } while ($running);
    ...
}   

使用流程图来描述一个任务的执行过程

Created with Raphaël 2.1.2 Start WorkCommand->runWorker Work->pop Work->getNextJob Worker->process 是否达到最大执行次数? Worker->logFailedJob failer->log job->delete job->failed this->raiseFailedJobEvent End RedisJob->fire CallQueuedHandler->call 是否执行异常,或超时? 任务是否被删除了? job->release (从新发布任务,并且尝试次数+1) job->delete (删除任务) RedisQueue->deleteReserved yes no yes no yes no

深入了解laravel消费队列的两种工作模式_第4张图片

再来说下redis中的任务是在何时被删除的,如何删除的

深入了解laravel消费队列的两种工作模式_第5张图片

当一个任务被lpop弹出之后,同时会将该认为添加到这个名字的队列中[当前队列名+:reserved],如上图,
在执行过程中如果任务在指定时间没有错误的正确执行完毕,那么这个任务会自动调用deleteReserved销毁, 假如执行有异常或者超时了,那么要判断任务的最大执行次数是否达到,没达到则再次release到队列中同时尝试次数加一,如果达到最大执行次数则执行执行失败,并将信息记录到数据库中.当然pop出消息前,还有一个步骤就是合并reserved,delayed的任务到队列中

你可能感兴趣的:(php,消息队列,queue,laravel,work,listen)