End.

消息队列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

End.