• 监听 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;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

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

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

      • 例如,如果你希望监听 key 的过期事件,你可以设置 Ex(E 代表 Keyevent 事件,x 代表过期事件):
        CONFIG SET notify-keyspace-events Ex
        
        • 1
      • 或者在 redis.conf 中添加:
        notify-keyspace-events Ex
        
        • 1
    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);
        
        • 1
    3. 确保 Redis 版本支持
      确保你使用的 Redis 版本支持键空间通知。虽然大多数现代版本都支持,但是如果你使用的是较旧的版本,可能会有问题。

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

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

    6. 测试和调试

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

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

  • 相关阅读:
    【1++的C++进阶】之智能指针
    SpringBoot+Selenium模拟用户操作浏览器
    漫谈:C语言 C++ 所有编程语言 =和==的麻烦
    阿里云OSS前端直传+net core后端签名
    HAProxy的详解和使用
    红黑树代码实现过程详解
    rsync+inotify实现数据同步
    《向量数据库指南》——向量数据库和关系型数据库的区别?
    手把手教大家在自己的Windows电脑上搭建一个视频电话系统(基于开源项目FreeSwitch+Linphone)
    【BOOST C++ String专题02】数字和字符串转化
  • 原文地址:https://blog.csdn.net/sunyuhua_keyboard/article/details/138614440