首先讲解一下何为异步消息队列:
所谓消息队列,就是一个以队列数据结构为基础的一个实体,这个实体是真实存在的,比如程序中的数组,数据库中的表,或者redis等等,都可以。
异步队列的作用:
个人认为消息队列的主要特点是异步处理,主要目的是减少请求响应时间和解耦。所以主要的使用场景就是将比较耗时而且不需要即时(同步)返回结果的操作作为消息放入消息队列
thinkphp 关于队列指令的解释以及作用。
本文场景:
订单异常通知;用定时任务太耗资源,直接上异步消息队列;
首先:composer require topthink/queue
然后配置extra/queue.php,我这里用redis,
return [
'connector' => 'Redis', // Redis 驱动
'expire' => 60, // 任务的过期时间,默认为60秒; 若要禁用,则设置为 null
'default' => 'default', // 默认的队列名称
'host' => '127.0.0.1', // redis 主机ip
'port' => 6379, // redis 端口
'password' => '', // redis 密码
'select' => 0, // 使用哪一个 db,默认为 db0
'timeout' => 0, // redis连接的超时时间
'persistent' => false,
];
默认使用同步:
$trade_no = $request->get("trade_no","20181171008_20200316155853");
$jobData = ['trade_no'=>$trade_no,'order_' => time(), 'bizId' => uniqid() , 'a' => 1 ] ;
$order = Db::name("pay")->where(['TradeNo'=>$jobData['trade_no']])->find();
$handel = "appindexjobSendWarning@fire";
Queue::later(10,$handel,$jobData,'helloJobQueue');
异步队列,默认为文件缓存队列。
后台开启异步消息队列:
php think queue:listen --queue helloJobQueue
--queue queue listname;
![v2-65c8540b16dfdebd721119232d843361_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=6d9e70cf-d22e-eb11-8da9-e4434bdf6706&url=https://pic2.zhimg.com/v2-65c8540b16dfdebd721119232d843361_b.jpg)
效果图:
![v2-a9ec7dd8d1b10f8e7bb5544c1960635e_b.jpg](http://img-01.proxy.5ce.com/view/image?&type=2&guid=6d9e70cf-d22e-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-a9ec7dd8d1b10f8e7bb5544c1960635e_b.jpg)
queue:参数名称;
php think queue:listen
--queue helloJobQueue //监听的队列的名称
--delay 0 //如果本次任务执行抛出异常且任务未被删除时,设置其下次执行前延迟多少秒,默认为0
--memory 128 //该进程允许使用的内存上限,以 M 为单位
--sleep 3 //如果队列中无任务,则多长时间后重新检查,daemon模式下有效
--tries 0 //如果任务已经超过重发次数上限,则进入失败处理逻辑,默认为0
--timeout 60 //创建的work子进程的允许执行的最长时间,以秒为单位
当开启时后会发现:
![v2-bd5a41b11b2f971f70927a77ca2badd2_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=6d9e70cf-d22e-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-bd5a41b11b2f971f70927a77ca2badd2_b.jpg)
然后进程保活;
可配合supervisor使用,保证进程常驻
普通测试配置
nohup php think queue:listen --queue helloJobQueue &
现在我们去线上实现订单异常的推送:
$jobData
下面看job:
namespace appindexjob;
use appcommonlogicwechatWechatUtil;
use appcommonmodelOrg;
use orgEqptClass;
use thinkController;
use thinkDb;
use thinkdbQuery;
use thinkqueueJob;
class SendWarning extends Controller {
/*** 处理订单逻辑
* @param Job $job
* @param $data
* @return bool
*/
public function fire(Job $job, $data) {
if (//逻辑1){
$re = $this->sendMsg($value);
}elseif(//逻辑2 ){
$re = $this->sendMsg($value);
}elseif(//逻辑3){
$re = $this->sendMsg($value);
}elseif (//逻辑4){
$re = $this->sendMsg($value);
}elseif (//逻辑5) {
$re = $this->sendMsg($value);
}else{
// $job->release(2); //立即重新发送 延迟两秒
}
if ($re){
$job->delete();
}
}
if ($job->attempts() >=19){ //当处理时间大于19 次的是直接删除
$job->delete();
}
}
/** 发送微信模板消息
* @param $content
* @return boolean
*/
public function sendMsg($order){
$org_re = Org::where(['OrgId'=>$order['OrgId']])->find();
$org_name = $org_re['Name'];
$user_re = Db::name('user')->where(['memberWeixin' => $order['User']])->find();
$wechat = new WechatUtil();
$member_wxin = $org_re['orgWx'] ; //$org_re['user']['memberWeixin'];
// oplog('用户' . $user_re['memberWeixin']. $wechat->getError());
$data = [];
$data['first'] = ['value' => '用户'.$user_re['memberName'].'在您的站点加注', 'color' => '#173177'];
$data['keyword1'] = ['value' => '***', 'color' => '#173177'];
$data['keyword2'] = ['value' => $order['TradeNo'], 'color' => '#173177'];
$data['keyword3'] = ['value' => $user_re['memberName'], 'color' => '#FFAABB'];
$data['keyword4'] = ['value' => $order['Status'], 'color' => '#173177'];
$data['keyword5'] = ['value' => $order['PayDate'], 'color' => 'red'];
$data['remark'] = ['value' => '用户支付异常订单提醒', 'color' => '#173177'];
// 第一个参数 为用户openid 第二个参数模板id 第三个 为点击推送进入的url 第四个为模板数据
$re = $wechat->sendTemplateMsg($member_wxin, 'tmHMmiJ0wNlXcYKdXJGAzfoJ51JkpbEuh4tbEmgMmxY', '', $data);
// var_dump($re);
// while ($re == false) {
// $re = $wechat->sendTemplateMsg($member_wxin,'tmHMmiJ0wNlXcYKdXJGAzfoJ51JkpbEuh4tbEmgMmxY', '', $data);
// }
oplog('用户' . $user_re['memberWeixin'] . $wechat->getError());
return $re;
}
}
然后进程保活:
安装supervisord:yum install -y supervisord
其他的不要管太多应该:vim /etc/supervisord.conf
![v2-277ca17389de17054801288aa2fa8112_b.png](http://img-02.proxy.5ce.com/view/image?&type=2&guid=6d9e70cf-d22e-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-277ca17389de17054801288aa2fa8112_b.png)
里应该就是其他命令的配置文件目录
cd /etc/supervisord.d
touch payJob.ini
vim payJob.ini
payJob.ini的内容:
[program:payJob]
####php 我认为最好用 whereis命令看下php的执行文件在哪最好用绝对路径
####后面项目的执行文件
#### --tries 失败重试19次
#### --delay 延迟180的
#### 还有这个为啥会这么长 (3600 - 180)/180 = 19 在一小时内,这个为啥会这么长其实都是按需求来
command=php /****/think queue:work --daemon --tries 19 --delay 180 --queue helloJobQueue
autorestart=true ####自动开启
重启supervisord:systemctl restart supervisord
这个延迟消息队列队列用的数据类型就不是redis的list了
![v2-7a9993f684ea293a707fb4f66110906e_b.png](http://img-02.proxy.5ce.com/view/image?&type=2&guid=6d9e70cf-d22e-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-7a9993f684ea293a707fb4f66110906e_b.png)
这个是有序集合,然后score 就是用的时间戳;这里我认为设计非常好,巧妙运用了redis数据类型
![v2-14bd186f870579da00668fafb95f2559_b.jpg](http://img-03.proxy.5ce.com/view/image?&type=2&guid=6d9e70cf-d22e-eb11-8da9-e4434bdf6706&url=https://pic2.zhimg.com/v2-14bd186f870579da00668fafb95f2559_b.jpg)
然后尝试 ps -ef|grep php
![v2-1a2fc14d1a2db967d0f651c2e5878ee9_b.png](http://img-02.proxy.5ce.com/view/image?&type=2&guid=6d9e70cf-d22e-eb11-8da9-e4434bdf6706&url=https://pic2.zhimg.com/v2-1a2fc14d1a2db967d0f651c2e5878ee9_b.png)
再次kill?
kill 24746
ps -ef|grep php
![v2-394205347807db77397b7b206d01f001_b.png](http://img-02.proxy.5ce.com/view/image?&type=2&guid=6d9e70cf-d22e-eb11-8da9-e4434bdf6706&url=https://pic2.zhimg.com/v2-394205347807db77397b7b206d01f001_b.png)
nice