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 过期事件无效的问题可能有几个原因。以下是一些可能的原因和相应的解决方案:
-  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
 
- 例如,如果你希望监听 key 的过期事件,你可以设置 
-  监听错误的数据库: 
 在你的代码中,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);
 
- 修改代码以使用正确的数据库索引:
-  确保 Redis 版本支持: 
 确保你使用的 Redis 版本支持键空间通知。虽然大多数现代版本都支持,但是如果你使用的是较旧的版本,可能会有问题。
-  日志配置: 
 确保你的日志配置正确,以便可以看到log.info输出的相关信息。如果日志级别设置过高,可能导致这些信息未被记录。
-  检查连接工厂配置: 
 确保ReactiveRedisConnectionFactory正确配置并且能够与 Redis 服务器建立连接。
-  测试和调试: - 你可以尝试在 Redis 中手动发布消息到相应的频道,看看你的监听器是否能够捕捉到这些消息。
- 使用 Redis CLI 或客户端库测试键过期通知是否正常工作。
 
调整上述设置后,你的应用应该能够正确监听和响应 Redis 键过期事件。如果问题依旧,请进一步检查网络配置及权限设置。










