一、驱动的选择
使用数据库驱动
优点:不用安装其他的啦里啦杂的东西,直接用
缺点:要进行数据库迁移,产生工作数据表
.env文件中设置队列驱动为数据库
php artisan queue:table
创建队列用到的数据表
php artisan queue:table
执行migrate
# 会新建 database/migrations/{timestamp}_create_jobs_table.php 文件
php artisan migrate
.env文件示例
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=database
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.exmail.qq.com // QQ企业邮箱
MAIL_PORT=25 // 使用25端口
MAIL_USERNAME=xxxx@xxx.com // 发件人邮箱
MAIL_PASSWORD=*** // 密码或授权码
MAIL_ENCRYPTION=tls
使用redis驱动
安装redis
windows下
windows下载地址,下载运行安装即可。
打开一个cmd窗口使用cd命令切换目录到C:\redis
运行redis-server.exe redis.windows.conf
Linux下
# 看看有木有密码
/etc/redis.conf port6379
项目中使用 Composer 安装依赖
composer require "predis/predis:~1.0"
.env文件示例
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=honeybot
DB_USERNAME=root
DB_PASSWORD=root
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.exmail.qq.com
MAIL_PORT=465 // 使用465端口
MAIL_USERNAME=xxx@xxx.com
MAIL_PASSWORD=***
MAIL_ENCRYPTION=ssl // 使用465端口
二、失败任务记录(可有可无,看你自己想不想记录)
有时候队列中的任务会失败。Laravel 内置了一个方便的方式来指定任务重试的最大次数。当任务超出这个重试次数后,它就会被插入到 failed_jobs 数据表里面。我们可以使用queue:failed-table
命令来创建 failed_jobs 表的迁移文件
# 会新建 database/migrations/{timestamp}_create_failed_jobs_table.php 文件
php artisan queue:failed-table
接着使用 migrate Artisan 命令生成 failed_jobs 表:
php artisan migrate
三、创建任务
创建任务 = 搞一个生产者 = (其实就是写一个在队列中你想执行的业务逻辑),名字随意取,但最好遵守命名规范。
这个生成的文件大概分2部分:一是__construct() 构造方法 ;二是handle 队列执行方法(意思就是在队列执行的时候,就用你这里面写的代码)
使用以下 Artisan 命令来生成一个新的队列任务:
# 该命令会在 app/Jobs 目录下生成一个新的类
php artisan make:job SendReminderEmail
新生成的类:pp/Jobs/SendReminderEmail.php
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Util\L;
use Mail;
class SendReminderEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $orderInfo;
protected $email;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($orderInfo, $email)
{
$this->orderInfo = $orderInfo;
$this->email = $email;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
// Mail::send()的返回值为空,所以可以其他方法进行判断
Mail::send('emails.new_order_mail',
[
'order_number' => $this->orderInfo['order_number'],
'goods_name' => $this->orderInfo['goods_name'],
'goods_color' => $this->orderInfo['goods_color'],
'goods_num' => $this->orderInfo['goods_num']
],
function ($message) {
$to = $this->email;
$message->to($to)->subject('【xx商城新订单通知】');
});
// 返回的一个错误数组,利用此可以判断是否发送成功
if (count(Mail::failures()) >= 1) {
L::email("订单:" . $this->orderInfo['order_number'] . "的 " . $this->email . " 邮件通知发送失败");
}
}
}
任务分发
生产者,在控制器内使用dispatch方法调用即可
<?php
namespace App\Api\Controllers\Mail;
use App\Api\Controllers\BaseController;
use App\Repositories\Order\OrderRepository;
class MailController extends BaseController
{
public function __construct(OrderRepository $order)
{
$this->order = $order;
}
public function send()
{
$header_id = 3691;
$this->order->sendMail($header_id);
}
}
定义发送邮件的类,分发任务
/**
* @param $header_id
* @return mixed
* 发送邮件 队列
*/
public function sendMail($header_id)
{
try {
// 邮件内容
$orderInfo = OrderDetail::select('order_number', 'order_lines.*')
->leftJoin('order_headers', 'order_headers.uid', '=', 'header_id')
->where('header_id', $header_id)
->first();
$order['order_number'] = $orderInfo->order_number;
$order['goods_name'] = '嘻嘻' . $orderInfo->combo;
$order['goods_color'] = $orderInfo->color;
$order['goods_num'] = $orderInfo->quantity;
L::email("订单:" . $orderInfo->order_number);
// 邮件地址列表
$emailList = ["xxx@qq.com", "xxx@163.com"]; // 测试 邮件地址
// 推送任务入队列
foreach ($emailList as $email) {
dispatch(new SendReminderEmail($order, $email));
}
} catch (\Exception $e) {
}
}
新建邮件发送模板
// /resource/views/emailsnew_order_mail.blade.php
<div>你好,小程序商城收到新订单。</div>
<div>收货地址: {{$address}}</div>
<div>订单号: {{$order_number}}</div>
<div>商品名称: {{$goods_name}}</div>
<div>商品颜色: {{$goods_color}}</div>
<div>数量: {{$goods_num}}</div>
四、开始测试
开始之前,我们需要在命令行启动队列系统,队列在启动完成后会进入监听状态
php artisan queue:listen
五、运行队列进程
php artisan queue:work
六、配置 Supervisor
测试完成后,邮件发送成功,表示你已经成功啦~
but,如果是在生产环境,就不可能是像开发时启动一下队列发送一次,肯定是要有一定的监听和触发机制,所以Supervisor登场了。
supervisord 是进程管理的服务端,常驻进程辅助干活 supervisorctl 是客户端,用来执行查看、加载等命令