工作中,延迟消费的场景也是挺常见的,比如支付订单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 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) {
return new KeyExpirationEventMessageListener(redisMessageListenerContainer);
}
@EventListener(RedisKeyExpiredEvent.class)
public void callback(RedisKeyExpiredEvent redisKeyExpiredEvent) {
// 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后,我们写的监听事件被被执行,打印结果如下:



