Laravel入坑指南(11)——列隊

很高興,咱們來到了Laravel入坑指南的第11篇。這一系列的文章已經接近尾聲了,在這一節裏面,咱們一塊兒討論列隊的用法。php

列隊,顧名思義,將須要處理的任務一個一個排好隊,等待處理程序來處理。這機的列隊機制,適用於須要異步處理的任務。html

因此在這裏,咱們首先須要關注三個問題:誰來投遞任務?將任務投遞到哪裏?誰來處理任務?redis

 

一、誰來投遞任務?sql

在Laravel裏,任務的投遞和處理,都是由JOB類負責的。並且哪一個JOB類投遞的任務,就由那個JOB類進行處理(劃重點)。首先,執行如下命令,就能夠建立本身的JOB類:數據庫

php artisan make:job ProcessMyJob

這時,就會建立出/app/Jobs/ProcessMyJob.php。在這個類中,有一個構造函數,以及一個handle參數。構造函數的參數,就是分發任務時指定的參數,在獲取任務實例化JOB時,就將列隊中的任務參數傳遞進來;handle函數則是處理函數。編程

有了個這JOB類以後,咱們能夠在咱們須要投遞任務的地方(好比某個Controller裏)進行投遞:app

//投遞到默認列隊,默認列隊隊名由配置文件決定,通常叫做default
ProcessMyJob::dispatch("參數");

//投遞到名字爲default2的列隊
ProcessMyJob::dispatch("參數")->onQueue("myqueue");

如今問題來了,默認列隊和名爲myqueue的列隊分別在哪裏呢?異步

 

 

二、將任務投遞到哪裏?函數

關於這個問題,取決於配置文件/config/queue.php。在這個配置文件中,咱們須要關注兩個配置項:default和connections。學習

2.1 connections

'connections' => [

        'sync' => [
            'driver' => 'sync',
        ],

        'database' => [
            'driver' => 'database',
            'table' => 'jobs',
            'queue' => 'default',
            'retry_after' => 90,
        ],

        'beanstalkd' => [
            'driver' => 'beanstalkd',
            'host' => 'localhost',
            'queue' => 'default',
            'retry_after' => 90,
            'block_for' => 0,
        ],

        'sqs' => [
            'driver' => 'sqs',
            'key' => env('AWS_ACCESS_KEY_ID'),
            'secret' => env('AWS_SECRET_ACCESS_KEY'),
            'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
            'queue' => env('SQS_QUEUE', 'your-queue-name'),
            'region' => env('AWS_REGION', 'us-east-1'),
        ],

        'redis' => [
            'driver' => 'redis',
            'connection' => 'default',
            'queue' => env('REDIS_QUEUE', 'default'),
            'retry_after' => 90,
            'block_for' => null,
        ],

    ],

這個配置項,讓Laravel能夠用同步、數據庫、beanstalkd、亞馬遜sql以及redis的方法來保存列隊數據。固然,博主我的建議用redis來進行存儲,因此下面全部的示例也會以redis做爲例子進行討論。咱們在第6節中,已經配置完redis。若是還不明白的同窗,請返回查看第6節

根據上面所示connections配置項中,咱們只需在/.evn文件中添加一個配置項:

REDIS_QUEUE=default

這一項就是指定上面所說的默認列隊名字。當任務投遞時沒有指定名字,就會投遞到這個名下的列隊中。

2.2  default

這一項則是指定了名爲default的列隊,用哪一種方式保存列隊數據。由於上面的例子中,咱們要把任務投遞到名字爲myqueue的列隊中,因此咱們還須要一個名爲myqueue的列隊。因此咱們的配置以下:

在/.env配置文件中QUEUE_CONNECTION的值爲redis:

QUEUE_CONNECTION=redis

到這裏,咱們知道任務由誰投遞的,任務保存在哪裏。那麼在指定的地方投遞完任務後,由誰調用JOB的handle函數,對任務進行處理呢?就是咱們接下來關注的重點。

 

 

三、誰來處理任務?

在這裏,咱們須要操做系統長駐進程,一直監視着列隊是否有任務要處理。因此咱們仍是離不開php的命令行。咱們能夠用如下方式啓動監視進程:

#啓動對全部列隊的監聽
php artisan queue:work

#啓動對default和myqueue的監聽,default列隊的優先級會高於myqueue的優先級
php artisan queue:work --queue=default,myqueue

#在redis鏈接上啓動對email列隊的監聽
#這種狀況就不須要在配置文件中寫email列隊的配置項
php artisan queue:work redis --queue=email

#列隊清空後就退出
php artisan queue:work --stop-when-empty

#啓動兩個監聽進程,兩個列隊沒有優先級關係
php artisan queue:work --queue=default
php artisan queue:work --queue=myqueue

被監聽的列隊,一旦有任務存在,監聽進程就會實例化對應的JOB類,並調用handle函數進行處理。

 

 

四、萬一監聽進程掛了,怎麼辦?

爲了解決這個問題,官方文檔介紹了能夠用Linux下的supervisor進行進程守護。如今讓咱們簡單探討

在CentOS下安裝supervisor只須要執行:

yum install supervisor

安裝完成後在就會建立出/etc/supervisord.conf配置文件和/etc/supervisord.d目錄。其中,配置文件中有如下配置項:

[include]
files = supervisord.d/*.ini

全部的進程守護配置文件都存放在/etc/supervisord.d路徑中。

安裝完成後,咱們須要建立啓動腳本/etc/init.d/supervisor

#!/bin/sh

# Source init functions
. /etc/rc.d/init.d/functions

prog="supervisord"

prefix="/usr/local"
exec_prefix="${prefix}"
prog_bin="${exec_prefix}/bin/supervisord"
PIDFILE="/var/run/$prog.pid"

start()
{
       echo -n $"Starting $prog: "
       daemon $prog_bin -c /etc/supervisord.conf --pidfile $PIDFILE
       [ -f $PIDFILE ] && success $"$prog startup" || failure $"$prog startup"
       echo
}

stop()
{
       echo -n $"Shutting down $prog: "
       [ -f $PIDFILE ] && killproc $prog || success $"$prog shutdown"
       echo
}

case "$1" in

 start)
   start
 ;;

 stop)
   stop
 ;;

 status)
       status $prog
 ;;

 restart)
   stop
   start
 ;;

 *)
   echo "Usage: $0 {start|stop|restart|status}"
 ;;

esac

接下來,讓咱們進行一下測試,看看supervisor是否有效。建立一個配置文件:

/etc/supervisord.d/myqueue.ini

[program:myqueue]
process_name=%(program_name)s_%(process_num)02d
command=php /www/wwwroot/default/artisan queue:work
autostart=true
autorestart=true
numprocs=4
redirect_stderr=true
stdout_logfile=/tmp/test.out.log

建立完成後,執行

/etc/init.d/supervisor restart

會發現咱們的列隊監視進程已經啓動,而且在咱們kill掉進程時會自動重啓。

到這裏,咱們列隊的話題大功告成。

 

 

最後咱們關注上一節遺留下的最後一個問題,關於事件Listener處理。如裏咱們須要以列隊進行事件的處理,咱們只須要讓偵聽器實現ShouldQueue接口便可:

<?php
namespace App\Listeners;

use Illuminate\Contracts\Queue\ShouldQueue;

class MyListener implements ShouldQueue
{
    /**
     * 任務將被推送到的鏈接名稱.
     *
     * @var string|null
     */
    public $connection = 'redis';

    /**
     * 任務將被推送到的列隊名稱.
     *
     * @var string|null
     */
    public $queue = 'queue_name';

    /**
     * 任務被處理以前的延遲時間(秒)
     *
     * @var int
     */
    public $delay = 60;
}

 

 

---------------------------  我是可愛的分割線  ----------------------------

最後博主借地宣傳一下,漳州編程小組招新了,這是一個面向漳州青少年信息學/軟件設計的學習小組,有意向的同窗點擊連接,聯繫我吧。

相關文章
相關標籤/搜索