场景描述
-
电商平台,客户下单未支付,会有锁库存的操作,支付有效时间为15min,15分钟之后订单失效,释放库存,修改订单状态。如何实现?
-
默认已连接redis,并在springboot引入依赖
修改redis.conf配置,以拿到发布的key
继承事件监听器,重写onMessage方法
public class KeyExpiredListener extends KeyExpirationEventMessageListener {
private static final Logger LOGGER = LoggerFactory.getLogger(KeyExpiredListener.class);
public KeyExpiredListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
@Override
public void onMessage(Message message, byte[] pattern) {
String channel = new String(message.getChannel(),StandardCharsets.UTF_8);
String key = new String(message.getBody(),StandardCharsets.UTF_8);
String patternStr = new String(message.getBody(),StandardCharsets.UTF_8);
LOGGER.info("key失效:channel:{},key:{},patternStr:{}",channel,key,patternStr);
// 取到逾期支付订单的id
if (!StringUtils.isEmpty(key) && key.startsWith("orderId:")){
String[] split = key.split(":");
Long orderId = Long.parseLong(split[1]);
// TODO 进行更改状态的操作
}
}
}
编写配置类,注入Bean
@Configuration
public class RedisConfiguraion {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(){
RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
return redisMessageListenerContainer;
}
@Bean
public KeyExpiredListener keyExpiredListener(){
return new KeyExpiredListener(redisMessageListenerContainer());
}
@Bean
// @0表示只监听0号库的失效key,*表示监听所有
public PatternTopic patternTopic(){
return new PatternTopic("__keyevent@0__:expired");
}
}
测试结果
存在缺陷
- redis的pus/sub不管有没有收到信息,都只发一次!存在网络抖动,发生异常等,意味着可能存在监听丢失,逾期订单不取消。
- redis-key单线程,同一时间大量失效,可能存在延迟。
- 如果orderservice服务是集群配置,所有客户端都会收到key失效的event;此时加上redis分布式锁处理。