实验场景:页面被客户访问发送邮件通知到我的邮箱,该场景只是为了测试,下单发送邮件或者短信的场景都是一样的,为了体现出来队列的优越性,我自己封装了个邮件发送的接口,接口内部实现增加了sleep(5),纯粹是为了给接口增加耗时,更好的达标实验效果。
workerman的redis-queue地址:
https://github.com/walkor/redis-queue
自己封装的邮件发送接口地址:
如果在页面里面直接调用发送邮件接口的话,页面需要等待5秒才能加载出来。代码实现如下
//直接调用, 在接口方故意模拟sleep( 5 ), 下面就会等5秒,上面就不用等直接扔给队列执行
$html = '被访问了下' . date ( 'Y-m-d H:i:s' );
$apiurl = 'http://phpmailer.wlphp.com/sendmail_api.php?html=' . urlencode ( $html ) . '&recipient=613154514@qq.com&subject=workerman的redis消息队列消息' ;
echo file_get_contents ( $apiurl );
消息队列实现:该页面在是thinkphp5的mvc框架里面首先在核心函数库放入如下函数:
//有时候一些项目运行在apache或者php-fpm环境,无法使用workerman/redis-queue项目,可以参考如下函数实现发送
function redis_queue_send ( $redis , $queue , $data , $delay = 0 ) {
$queue_waiting = 'redis-queue-waiting' ;
$queue_delay = 'redis-queue-delayed' ;
$now = time ();
$package_str = json_encode ([
'id' => rand (),
'time' => $now ,
'delay' => 0 ,
'attempts' => 0 ,
'queue' => $queue ,
'data' => $data
]);
if ( $delay ) {
return $redis -> zAdd ( $queue_delay , $now + $delay , $package_str );
}
return $redis -> lPush ( $queue_waiting . $queue , $package_str );
}
在页面控制器对应方法里面调用这个函数把要发送邮件信息添加到消息队列里面实现代码如下:
//基于redis的消息队列服务
$html = '被访问了下' . date ( 'Y-m-d H:i:s' );
$redis = new \ Redis ;
$redis -> connect ( '127.0.0.1' , 6379 );
$queue = 'user-1' ;
$data = [ date ( 'Y-m-d H:i:s' ), $html ];
redis_queue_send ( $redis , $queue , $data );
mvc框架里面只需要把消息仍进队列,不管邮件是否发送成功,所以不会造成阻塞,页面加载速度基本不受影响。
页面多刷新几次然后打开redis能够看见如下队列:
启动基于wokerman的消费者端:注意生产者在mvc框架里面,随时把消息添加到队列。消费者端基于cli命令行方式启动。
php index.php start
启动之后如下:消息被依次消费发送邮件
<?php
require __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
use Workerman\Lib\Timer;
use Workerman\RedisQueue\Client;
$worker = new Worker();
$worker->onWorkerStart = function () {undefined
$client = new Client('redis://127.0.0.1:6379');
$client->subscribe('user-1', function($data){undefined
echo "user-1\n";
var_export($data);
//调用发送邮件接口
$html=$data[1];
$apiurl="http://phpmailer.wlphp.com/sendmail_api.php?html=".urlencode($html)."&recipient=613154514@qq.com&subject=workerman的redis消息队列消息";
echo file_get_contents($apiurl);
});
};
Worker::runAll();