工作中,延迟消费的场景也是挺常见的,比如支付订单30分钟未支付取消,点餐、打车10分钟无人接自动取消等,延迟消费单应用环境可以使用JDK的DelayQueue来实现,分布式环境就要引入三方组件来实现了,可以实现的有 MQ,Redis等,本文教大家用 Redis的监听key超时来实现延迟消费,
如:生成订单时,将订单作为key写入redis,并设置超时时间,如果订单支付就删除这个key(删除并不会触发key的自动失效事件),如无后续操作,就会在等待30分钟后,触发key的超时事件,进入我们设置的业务后续处理流程。
需要注意的是,这样做很危险,消费方一旦宕机,这个key事件就相当于被略过了,而且我们也无从得知了,如搭建高可用的集群环境消费的话,需要注意不要被重复消费了。
要监听redis的key失效,首先需要开启redis的相关配置,如下,默认是被注释掉的

pom yaml 略,同上文无变化,配置类如下,注释掉上文无关内容,大家看变化
@AllArgsConstructor
@SpringBootConfiguration
public class RedisPubsubConfig {
private final RedisConnectionFactory redisConnectionFactory;
// 依赖搜索
// private final List<RedisMessagePublisher> redisMessagePublisherList;
// redis消息监听器容器
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer() {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisConnectionFactory);
// 统一注册redis消息监听器
// redisMessagePublisherList.forEach(redisMessagePublisher -> container.addMessageListener(redisMessagePublisher, redisMessagePublisher.subTopic()));
return container;
}
// 监听redis key失效事件
@Bean
public KeyExpirationEventMessageListener keyExpiredListener(RedisMessageListenerContainer redisMessageListenerContainer) {
/**
* 监听器已由spring实现,接收到redis key失效事件时,会发布一个spring容器事件RedisKeyExpiredEvent
* {@link org.springframework.data.redis.connection.MessageListener}
*/
return new KeyExpirationEventMessageListener(redisMessageListenerContainer);
}
@EventListener(RedisKeyExpiredEvent.class)
public void callback(RedisKeyExpiredEvent redisKeyExpiredEvent) {
/*
* 此处可以拿到失效的key,拿不到已经失效的key的value值,追到顶层接口
* org.springframework.data.redis.connection.MessageListener#onMessage也没看到
* 拿不到value的话,可操作性就没那么大了,比如,对于一个取消订单操作,生成的方式不同,取
* 消时的逻辑也是有所差异,我们可以key存订单,value存订单类型(微信支付/支付宝支付等)
* ,这里拿不到value的话,也就不那么方便了,虽然也可以拼串存key里,处理起来不仅麻烦也不
* 够“优雅”,哈哈,大家要是知道怎么拿到失效key的value可以告诉下我哈
*/
// id 是key
byte[] id = redisKeyExpiredEvent.getId();
System.out.println("id:" + new String(id, StandardCharsets.UTF_8));
// source 也是key
byte[] source = redisKeyExpiredEvent.getSource();
System.out.println("source:" + new String(source, StandardCharsets.UTF_8));
// 不知道是啥,null,反正也不关心
String keyspace = redisKeyExpiredEvent.getKeyspace();
System.out.println("keyspace:" + keyspace);
// 应该是失效key的value吧?但是是null
Object value = redisKeyExpiredEvent.getValue();
System.out.println("value:" + value);
// 时间戳
long timestamp = redisKeyExpiredEvent.getTimestamp();
System.out.println("timestamp:" + timestamp);
}
}简单的贴一下测试结果:
设置一个key,10s后超时

10s后,我们写的监听事件被被执行,打印结果如下:

版权声明:本文为qq_40553917原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。