监听 Redis key 过期事件无效的问题

import com.shgbitai.manmachineability.constance.RedisKeyPrefix;
import com.shgbitai.manmachineability.service.RedisService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.ReactiveRedisMessageListenerContainer;
import org.springframework.stereotype.Component;

import java.util.Optional;

@Component
@Slf4j
public class RedisKeyExpirationListenerConfig {

	@Resource
	private RedisService redisService;

	@Bean
	ReactiveRedisMessageListenerContainer keyExpirationListenerContainer(ReactiveRedisConnectionFactory connectionFactory, @Value("${spring.data.redis.database}") String databaseIndex) {
		ReactiveRedisMessageListenerContainer container = new ReactiveRedisMessageListenerContainer(connectionFactory);

		// 订阅过期事件。这里的"__keyevent@0__:expired"是监听默认数据库中Key过期事件的频道。
		// 如果你的应用使用的不是默认数据库,需要更改这里的数字。
		String expiredTopic = String.format("__keyevent@%s__:expired", 0);

		container.receive(ChannelTopic.of(expiredTopic))
				.doOnNext(message -> {
					// 此处处理接收到的过期Key。message.getMessage()包含了过期的Key。
					String expiredKey = message.getMessage();
					log.info("会话过期的key: " + expiredKey);
					//如果session聊天室会话时长过期,通知前端,会话关闭
					if(expiredKey.contains(RedisKeyPrefix.SESSION_LAST_ACTIVITY_KEY_PREFIX)){
						String sessionId = Optional.of(expiredKey)
								.filter(s -> s.contains(":"))
								.map(s -> s.substring(s.indexOf(":") + 1)).orElse("");
						log.info("会话关闭,过期的会话SessionId:{}",sessionId);
						redisService.setWebSocketSessionExpired(sessionId);
					}
				})
				.subscribe();

		return container;
	}
}

监听 Redis key 过期事件无效的问题可能有几个原因。以下是一些可能的原因和相应的解决方案:

  1. Redis 配置未启用过期事件通知
    默认情况下,Redis 可能没有启用键过期事件的通知。你需要在 Redis 的配置文件 redis.conf 中设置 notify-keyspace-events 选项,或者通过运行 CONFIG SET 命令动态设置。

    • 例如,如果你希望监听 key 的过期事件,你可以设置 Ex(E 代表 Keyevent 事件,x 代表过期事件):
      CONFIG SET notify-keyspace-events Ex
      
    • 或者在 redis.conf 中添加:
      notify-keyspace-events Ex
      
  2. 监听错误的数据库
    在你的代码中,String expiredTopic = String.format("__keyevent@%s__:expired", 0); 这一行硬编码了数据库索引为 0。如果你的应用使用的不是数据库 0,则需要修改这个索引以匹配你实际使用的数据库。你已经通过注解 @Value("${spring.data.redis.database}") String databaseIndex 获取了数据库索引,但是没有使用它来格式化 expiredTopic

    • 修改代码以使用正确的数据库索引:
      String expiredTopic = String.format("__keyevent@%s__:expired", databaseIndex);
      
  3. 确保 Redis 版本支持
    确保你使用的 Redis 版本支持键空间通知。虽然大多数现代版本都支持,但是如果你使用的是较旧的版本,可能会有问题。

  4. 日志配置
    确保你的日志配置正确,以便可以看到 log.info 输出的相关信息。如果日志级别设置过高,可能导致这些信息未被记录。

  5. 检查连接工厂配置
    确保 ReactiveRedisConnectionFactory 正确配置并且能够与 Redis 服务器建立连接。

  6. 测试和调试

    • 你可以尝试在 Redis 中手动发布消息到相应的频道,看看你的监听器是否能够捕捉到这些消息。
    • 使用 Redis CLI 或客户端库测试键过期通知是否正常工作。

调整上述设置后,你的应用应该能够正确监听和响应 Redis 键过期事件。如果问题依旧,请进一步检查网络配置及权限设置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MonkeyKing.sun

对你有帮助的话,可以打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值