消息队列30分钟订单超时自动取消(三种情况下解决方法)
1、情况一: 没有使用到别的框架封装的Queue
1.1 开启监听 键过期 vi /etc/redis.conf notify-keyspace-events "Ex"
1.2 添加键值 $orderId = mt_rand(100, 999); Yii::$app->redis3->setex('ORDER_CONFIRM:' . $orderId, 30, $orderId);// 30秒后过期--执行取消订单
1.3 添加监听 文件 console/controllers/AaController.php
$redis = new \Redis();
$redis->connect("192.168.30.80", 6379);
$redis->psubscribe(array('__keyevent@3__:expired'), function ($redis, $pattern, $channel, $messag) {
date_default_timezone_set('PRC');
echo 'functionCallBack:' . date('H:i:s') . "\n";
file_put_contents('/tmp/debug.log', '时间:' . date('H:i:s', time()) . "\n\n", 8);
file_put_contents('/tmp/debug.log', var_export($redis, 1) . "\n", 8);
file_put_contents('/tmp/debug.log', var_export($pattern, 1) . "\n", 8);
file_put_contents('/tmp/debug.log', var_export($channel, 1) . "\n", 8);
file_put_contents('/tmp/debug.log', var_export($messag, 1) . "\n\n\n", 8);
});
启动监听: php console/controllers/AaController.php
日志显示 callbackFun 回调的第四个参数 是我们需要的参数 ORDER_CONFIRM:375 利用 回调时候,可以再添加一个队列(lpush/rpush 入队) 然后另一个监听使用阻塞 blpop (brpop)取出数据,进行订单取消等业务处理 或者: 直接在回调时候,进行订单取消业务处理
redis 的默认连接是有超时的 laravel关闭配置如下
'redis' => [
'client' => 'predis',
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => env('REDIS_DB', 0),
'read_write_timeout' => env('REDIS_RW_TIMEOUT', -1), // 读写超时设定
],
],
即,.env文件,REDIS_RW_TIMEOUT设置-1即可 PHP直接设置:ini_set('default_socket_timeout', -1);
1.4 lpush实现 和 brpop 两监听事件 详细代码 console/controllers/AA.php 文件
<?php
/**
* 键过期,lpush 入队
*/
ini_set('default_socket_timeout', -1);
$redis = new \Redis();
$redis->connect("192.168.30.80", 6379);
$redis->psubscribe(array('__keyevent@3__:expired'), function ($redis, $pattern, $channel, $keyName) {
date_default_timezone_set('PRC');
$orderId = explode(':', $keyName);
$orderId = isset($orderId[1]) ? $orderId[1] : 0;
$redis = new \Redis();
$redis->connect("192.168.30.80", 6379);
$redis->select(3);
$redis->lpush('CancelOrderQueue', $orderId);
echo 'functionCallBack:' . date('H:i:s') . ' $orderId = ' .$orderId . "\n";
file_put_contents('/tmp/debug.log', '时间:' . date('H:i:s', time()) . "\n", 8);
file_put_contents('/tmp/debug.log', var_export($orderId, 1) . "\n\n\n", 8);
});
console/controllers/AB.php 文件
<?php
/**
* brpop出队
*/
ini_set('default_socket_timeout', -1);
$redis = new \Redis();
$redis->connect("192.168.30.80", 6379);
$redis->select(3);
while (true) {
$res = $redis->brpop('CancelOrderQueue', 0);
date_default_timezone_set('PRC');
file_put_contents('/tmp/debug.log', '时间:' . date('H:i:s', time()) . "\n", 8);
file_put_contents('/tmp/debug.log', var_export('brpop消费消息:', 1) . "\n", 8);
file_put_contents('/tmp/debug.log', var_export($res, 1) . "\n\n\n", 8);
}
使用supervisor守护进程 php console/controllers/AA.php php console/controllers/AB.php 参考《centos安装Supervisor以及简单配置(添加进程守护)》https://www.yxccan.cn/blog/detail/32
2、情况二、直接使用laravel的Queue的delay 延迟任务 延迟30分钟执行即可 参考《laravel基于redis,使用消息队列(邮件推送)》https://blog.yxccan.cn/blog/detail/6
3、情况四、在Yii2中使用 Yii::$app->queue->delay(1800)->push(new ImportUserJob($v)); composer安装 yiisoft/yii2-queue 直接使用queue的delay 延迟任务 delay(1800);//阻塞30分钟 参考《Yii2队列的简单使用》https://blog.yxccan.cn/blog/detail/29