高性能离不开异步,异步离不开队列。
下面将介绍Laravel框架怎么使用队列进行一些异步处理。
在系统很多模块可能同步处理需要很长时间,比如发送邮件、视频转码、日志存储等。
假如系统处理这些功能模块都是使用同步处理的话,那么系统性能必将大大降低。
所以我们可以考虑异步进行处理这些长进程任务。
下面将介绍laravel的队列,即可以实现异步处理这些任务。
关于队列入门知识可以参考《[redis消息队列简单应用](http://blog.yxccan.cn/blog/detail/3 "redis消息队列简单应用")》
#### 概括
1. laravel队列配置(配置文件 .env 和 config/queue.php)
2. 创建队列任务类(app/Jobs/xxx.php)
3. 控制器将数据添加到队列中
4. 启动队列
5. 设置API路由,执行请求,执行队列任务
6. 使用Supervisor将队列任务启动 添加到守护进程中
------------
### 1. laravel队列配置(配置文件 .env 和 config/queue.php)
优先配置文件 .env 如下:
```php
QUEUE_DRIVER=redis #队列驱动 更改使用 redis
# 其它不设置 则会使用 config/queue.php 里面的配置参数
```
当.env 文件没有配置 或者 设置变量为空时,则会按照 config/queue.php 文件的配置信息运行laravel
config/queue.php 文件如下:
```php
'default' => env('QUEUE_DRIVER', 'redis'), //修改队列驱动,使用redis
'connections' => [
//...省略其它驱动
//redis驱动
'redis' => [
'driver' => 'redis',
'connection' => 'email', //连接redis的配置 email节点
'queue' => 'default', //默认使用default队列 键名
'retry_after' => 90, //该配置项的目的是定义任务在执行以后多少秒后释放回队列
'block_for' => null,
],
],
'failed' => [
'database' => env('DB_CONNECTION', 'mysql'),//队列执行失败 存放的数据库
'table' => 'failed_jobs',//队列执行失败 存放的表
],
```
### 2. 创建队列任务类(app/Jobs/xxx.php)
在app/Jobs 目录下创建执行队列任务的类,若没有Jobs文件夹,则可以自己创建;
或者使用artisan命令 创建队列任务类,命令如下:
php artisan make:job SendEmailCode
执行后,将会生成 app/Jobs/SendEmailCode.php
其中handle()方法为任务执行方法,如下代码为发送邮件的源码:
app/Jobs/SendEmailCode.php 代码如下:
```php
data = $data;
}
/**
* @param Mailer $mailer
*/
public function handle(Mailer $mailer)
{
$data = $this->data;
$mailer->end('email.sendCode', ['data' => $data], function ($message) use ($data) {
$message->to($data['email'])->subject('【' . $data['code'] . '】重要操作验证码 - YXC-Blog');
});
}
}
```
代码解析:其中handle中执行了发送邮件的方法Mailer类下的send()方法,详情可以阅读《[laravel 通过smtp发送邮件配置、相关示例](http://blog.yxccan.cn/blog/detail/4 "laravel 通过smtp发送邮件配置、相关示例")》
$data:为规定的数组数据,需要控制器调用添加队列时传值过来。
### 3. 控制器将数据添加到队列中
创建一个控制器,将数据添加到队列中
在app/Http/Controllers/目录下创建MailController.php 文件
或者使用artisan 命令进行创建
如下是发送验证码的控制器代码:
```php
get('email');
$resArray = [
'code' => 0,
'msg' => '发送成功'
];
if (preg_match('/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,5}){1,2})$/', $email)) {
$resArray['code'] = 1;
$data['email'] = $email;
$data['code'] = mt_rand(1000, 999999);
//...其它操作
//添加邮件队列
$this->dispatch((new SendEmailCode($data))->onQueue('sendEmailCode'));
} else {
$resArray['msg'] = '邮箱格式不正确';
}
return $resArray;
}
}
```
代码解析:
$this->dispatch((new SendEmailCode($data))->onQueue('sendEmailCode'));
其中dispatch()方法为分发任务的核心方法,方法里传一个任务类的实例。
3.1) dispatch()->onConnection('database') :更改任务的连接,将连接数据库进行存储队列
3.2) ->onQueue('sendEmailCode') :更改使用的队列名称
3.3) ->delay(now()->addMinutes(10)) :创建后延迟10分钟执行队列
### 4. 启动队列
Laravel 自带了一个队列进程用来处理被推送到队列的新任务。你可以使用 queue:work 命令运行这个队列进程。请注意,队列进程开始运行后,会持续监听队列,直至你手动停止或关闭终端
请记住,队列进程是长生命周期的进程,会在启动后驻留内存。若应用有任何改动将不会影响到已经启动的进程。所以请在发布程序后,重启队列进程。
最简单的启动命令:
php artisan queue:work
但是以上命令,只会执行default队列,所以不是我们实际想要的。所以需要以下启动命令
4.1 php artisan queue:work --queue=sendEmailCode
指定启动sendEmailCode队列
4.2 php artisan queue:work redis --queue=emails
指定启动redis连接下的sendEmailCode队列
4.3 php artisan queue:work --queue=higher,high,low ...
指定队列执行的优先级
4.4 php artisan queue:restart
重启队列
4.5 php artisan queue:work --timeout=60
队列进程 queue:work 可以设定超时 --timeout 项。该 --timeout 控制队列进程执行每个任务的最长时间,如果超时,该进程将被关闭。
注:参数项 --timeout 的值应该始终小于配置项 retry_after 的值,这是为了确保队列进程总在任务重试以前关闭。如果 --timeout 比retry_after 大,那么你的任务可能被执行两次。
4.6 php artisan queue:work --sleep=3
休眠时间,每执行一个任务后休眠3秒
4.7 启动监听三种情况:
4.7.1 queue:work
默认只执行一次队列请求, 当请求执行完成后就终止;
4.7.2 queue:listen
监听队列请求, 只要运行着, 就能一直接受请求, 除非手动终止;
4.7.3 queue:work --daemon
同 listen 一样, 只要运行着, 就能一直接受请求, 不一样的地方是在这个运行模式下, 当新的请求到来的时候, 不重新加载整个框架, 而是直接 fire 动作.
能看出来, queue:work --daemon 是最高级的, 一般推荐使用这个来处理队列监听.
注意: 使用 queue:work --daemon , 当更新代码的时候, 需要停止, 然后重新启动, 这样才能把修改的代码应用上
### 5. 设置API路由,执行请求,执行队列任务
在 routes/api.php 设置 刚刚的邮件控制器的路由
代码如下:
```php
//发送邮箱验证码
Route::post('sendEmailCode', 'MailController@sendEmailCode');
```
如下我们使用postman发送post请求即可以测试发送邮件队列了
请求地址 //localhost/api/sendEmailCode
![](https://blog-1252087744.cos.ap-guangzhou.myqcloud.com/2019-04/laravel%E5%9F%BA%E4%BA%8Eredis%EF%BC%8C%E4%BD%BF%E7%94%A8%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%EF%BC%88%E9%82%AE%E4%BB%B6%E6%8E%A8%E9%80%81%EF%BC%89/1.jpg)
观察redis是否有队列数据
![](https://blog-1252087744.cos.ap-guangzhou.myqcloud.com/2019-04/laravel%E5%9F%BA%E4%BA%8Eredis%EF%BC%8C%E4%BD%BF%E7%94%A8%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%EF%BC%88%E9%82%AE%E4%BB%B6%E6%8E%A8%E9%80%81%EF%BC%89/2.jpg)
观察进程,我这边使用windows的测试
![](https://blog-1252087744.cos.ap-guangzhou.myqcloud.com/2019-04/laravel%E5%9F%BA%E4%BA%8Eredis%EF%BC%8C%E4%BD%BF%E7%94%A8%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%EF%BC%88%E9%82%AE%E4%BB%B6%E6%8E%A8%E9%80%81%EF%BC%89/3.jpg)
成功,邮件也收到了
![](https://blog-1252087744.cos.ap-guangzhou.myqcloud.com/2019-04/laravel%E5%9F%BA%E4%BA%8Eredis%EF%BC%8C%E4%BD%BF%E7%94%A8%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%EF%BC%88%E9%82%AE%E4%BB%B6%E6%8E%A8%E9%80%81%EF%BC%89/4.jpg)
### 6. 使用Supervisor将队列任务启动 添加到守护进程中
推荐安装Supervisor,将 php artisan queue:work --queue sendEmailCode 等一系列队列进程,添加到进程保护中,防止中途崩溃时候,可以自救,哈哈~😄
关于Supervisor,可以参考《[centos安装Supervisor以及简单配置(添加进程守护)](http://blog.yxccan.cn/blog/detail/32 "centos安装Supervisor以及简单配置(添加进程守护)")》
------------
#### 总结
1. laravel队列配置(配置文件 .env 和 config/queue.php)
2. 创建队列任务类(app/Jobs/xxx.php)
3. 控制器将数据添加到队列中
4. 启动队列
5. 设置API路由,执行请求,执行队列任务
6. 使用Supervisor将队列任务启动 添加到守护进程中
------------
the End.