很高興,咱們來到了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; }
--------------------------- 我是可愛的分割線 ----------------------------
最後博主借地宣傳一下,漳州編程小組招新了,這是一個面向漳州青少年信息學/軟件設計的學習小組,有意向的同窗點擊連接,聯繫我吧。