10
11月
2021
1.修改redis 配置
开启redis.conf 文件中 notify-keyspace-events Ex
或者 在redis-cli 客户端输入如下命令:
config set notify-keyspace-events Ex
2.修改laravel database.php(可选,查阅资料的时候发现有部分使用者需要调整实例才能使用)
//datebase.php配置页面
'redis' => [
'client' => 'predis',
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
"queue" => '{default}',//queue站点默认走的redis
],
'publisher' => [ //redis 订阅监听
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
"read_write_timeout"=>0,//长连接不要断
],
]
php artisan make:command OrderExpireListen
app\Console\Commands\OrderExpireListen.php文件
<?php
namespace App\Console\Commands;
use App\Model\Order;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
//use Illuminate\Redis;
class OrderExpireListen extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'order:expire';
/**
* The console command description.
*
* @var string
*/
protected $description = '监听订单创建,在1分钟后如果没付款取消订单。';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
//经过多次测试 和查询资料 laravel 无法使用门面的redis 去监听失效效果 必须使用原生 具体原因未知
ini_set('default_socket_timeout', -1);
$redis = new \Redis();
$redis->connect('127.0.0.1', '6379');
// $redis=Redis::connection('publisher');//创建新的实例
$redis->psubscribe(['__keyevent@*__:expired'], function ($message, $channel) {
dd($message);
// Redis::set('aa','123');//这样就不会报错了。这里使用的是default的,是两个redis链接。
});
exit;
$cachedb = config('database.redis.cache.database', 0);
$pattern = '__keyevent@' . $cachedb . '__:expired';
$pattern = '__keyevent@0*__:expired';
Redis::psubscribe(['__keyevent@0__:expired'], function ($message, $channel) {
echo $channel.PHP_EOL;//订阅的频道
echo $message.PHP_EOL;//过期的key
echo '---'.PHP_EOL;
});
exit;
Redis::psubscribe([$pattern], function ($channel) { // 订阅键过期事件
var_dump($channel);
// laravel_cache:ORDER_CONFIRM:7 这样的格式
$channel = trim(strstr($channel, ':'), ':');
$key_type = str_before($channel, ':');
switch ($key_type) {
case 'ORDER_CONFIRM':
echo 1;
// $order_id = str_after($channel, ':'); // 取出订单 ID
// $order = Order::query()->find($order_id);
// if ($order) {
// // 执行取消操作
// $order->status = 2;
// $order->save();
// }
break;
case 'ORDER_OTHEREVENT':
break;
default:
break;
}
});
}
}
执行命令 php artisan order:expire 可直接执行该文件(不熟悉的可以查询文档说明)
4:在控制器中新增订单的方法中加入缓存。
Cache::store('redis')->put('ORDER_CONFIRM:'.$order->id,3,$order->id); // 3秒后过期。
Redis::setex('ORD/ER_CONFIRM:'.$order,$order,1);//上下同效果 我设定的$order = 3
运行上面的 php artisan order:expire 开启监听 然后执行目录文件 即可接收到监听消息
经过多次测试 和查询资料 laravel 无法使用门面的redis 去监听失效效果 必须使用原生 具体原因未知
方法二:延时队列
原理:利用有序集合的分值排序或者集合中过期符合要求的值,key为需要处理的数据
RedisHandler::getInstance()->zAdd(
$key,
//时间,
serialize(//订单号之类的数据)
);
$key,
//时间,
serialize(//订单号之类的数据)
);
执行逻辑
$result = RedisHandler::getInstance()->zRange($key, 0 ,0);
取出值,当符合要求后 通过zRem 删除该值
Redis::zadd('zlist',time()-86400,'b'.time());
$list = Redis::Zrange('zlist',0,time());
Redis::zRem('zlist',$list[0]);