1、服务器上redis配置
在 redis.conf 中配置
notify-keyspace-events Ex
或者通过命令行临时设置
redis-cli config set notify-keyspace-events Ex
2、框架中创建监听器
// app/listener/RedisKeyExpiredListener.php
namespace app\listener;
use support\Redis;
use Webman\Event\Event;
class RedisKeyExpiredListener
{
public function handle($event)
{
$key = $event['key'];
$channel = $event['channel'];
// 这里处理 key 过期的业务逻辑
echo "Key expired: {$key} at " . date('Y-m-d H:i:s') . "\n";
// 示例:处理订单超时
if (strpos($key, 'order:') === 0) {
$this->handleOrderTimeout($key);
}
// 示例:处理会话过期
if (strpos($key, 'session:') === 0) {
$this->handleSessionExpired($key);
}
}
private function handleOrderTimeout($key)
{
// 提取订单ID
$orderId = str_replace('order:', '', $key);
// 处理订单超时逻辑
// 例如:更新订单状态为已取消
echo "处理订单超时: {$orderId}\n";
// 这里可以调用你的业务逻辑
// Order::where('id', $orderId)->update(['status' => 'cancelled']);
}
private function handleSessionExpired($key)
{
// 处理会话过期逻辑
$sessionId = str_replace('session:', '', $key);
echo "会话过期: {$sessionId}\n";
}
}
3、redis订阅
// app/service/RedisExpireSubscriber.php
namespace app\service;
use support\Redis;
use Workerman\Worker;
use Webman\Event\Event;
class RedisExpireSubscriber
{
public function onWorkerStart()
{
// 只在其中一个 worker 进程中启动订阅
if (0 === Worker::$id) {
$this->subscribeKeyExpire();
}
}
private function subscribeKeyExpire()
{
// 创建独立的 Redis 连接用于订阅
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);
// 订阅键过期事件
$redis->psubscribe(['__keyevent@*__:expired'], function ($redis, $pattern, $channel, $key) {
// 触发事件处理
Event::emit('redis.key.expired', [
'key' => $key,
'channel' => $channel,
'timestamp' => time()
]);
});
}
}
4、配置事件监听
// config/event.php
return [
'redis.key.expired' => [
[app\listener\RedisKeyExpiredListener::class, 'handle'],
],
];
5、注册服务
// config/process.php
return [
// ... 其他进程配置
'redisExpireSubscriber' => [
'handler' => app\service\RedisExpireSubscriber::class,
'count' => 1, // 只需要一个进程来订阅
],
];
6、设置带过期时间的key
// 示例:设置订单超时
use support\Redis;
class OrderService
{
public function createOrder($orderId, $expireSeconds = 1800)
{
// 创建订单逻辑...
// 设置 Redis key 并指定过期时间
Redis::setEx("order:{$orderId}", $expireSeconds, 'pending');
echo "订单 {$orderId} 已创建,将在 {$expireSeconds} 秒后过期\n";
}
}
7、Example
// app/controller/OrderController.php
namespace app\controller;
use support\Request;
use support\Redis;
class OrderController
{
public function create(Request $request)
{
$orderId = uniqid('order_');
$data = $request->post();
// 保存订单到数据库
// Order::create([...]);
// 设置 Redis 过期监听(30分钟过期)
Redis::setEx("order:{$orderId}", 1800, json_encode([
'order_id' => $orderId,
'status' => 'pending',
'created_at' => time()
]));
return json([
'code' => 0,
'msg' => '订单创建成功',
'data' => ['order_id' => $orderId]
]);
}
}