SpringBoot监听redis键过期事件,实现订单超时关闭

SpringBoot监听redis键过期事件,实现订单超时关闭

场景

订单超时关闭,客户下单时未支付,超过一段时间会自动将订单修改为已关闭,不允许再次支付。类似的场景还有很多,只要用到有过期概念的都可以设计成该做法。

通常做法

  1. 通过定时任务每隔一段时间检查是否有超时订单,修改订单的状态,释放库存等等。
  2. 缺点:后台定时任务运行频繁,涉及订单操作业务比较复杂,增加服务器压力

思路

  1. 单机部署可以使用java8里面的DelayQueue延时队列,对超时的订单执行取消操作,同时缺点也存在,比如服务器宕机,那保存在内存的订单延时队列就被清空,对业务影响也比较大,建议和定时器结合使用。
  2. 使用redis存储过期键,当存储的键值过期时,发出事件通知,通知到程序,执行取消订单操作,不过同时也有宕机风险。因为 Redis 目前的订阅与发布功能采取的是发送即忘(fire and forget)策略, 所以如果你的程序需要可靠事件通知(reliable notification of events), 那么目前的键空间通知可能并不适合你:当订阅事件的客户端断线时, 它会丢失所有在断线期间分发给它的事件。并不能确保消息送达。未来有计划允许更可靠的事件传递,但可能这将在更一般的层面上解决,或者为Pub / Sub本身带来可靠性,或者允许Lua脚本拦截Pub / Sub消息来执行诸如推送将事件列入清单。

redis事件类型

    键空间通知(key-space) __keyspace@DB__:KeyPattern 键事件通知(key-event)__keyevent@DB__:OpsType

开启配置

修改redis.conf配置文件notify-keyspace-events 为 notify-keyspace-events Ex,这里Ex分别代表键过期事件。

=

    K:keyspace 事件,事件以 keyspace@ 为前缀进行发布 E:keyevent 事件,事件以 keyevent@ 为前缀进行发布 g:一般性的,非特定类型的命令,比如del,expire,rename等 $:字符串特定命令 l:列表特定命令 s:集合特定命令 h:哈希特定命令 z:有序集合特定命令 x:过期事件,当某个键过期并删除时会产生该事件 e:驱逐事件,当某个键因 maxmemore 策略而被删除时,产生该事件 A:g$lshzxe的别名,因此”AKE”意味着所有事件

Springboot使用redis事件监听器

RedisListenerConfig.java

@Configuration
public class RedisListenerConfig {
          
   

    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
          
   
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        return container;
    }
}

RedisKeyExpirationListener.java

@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
          
   

    public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
          
   
        super(listenerContainer);
    }
    @Override
    public void onMessage(Message message, byte[] pattern) {
          
   

        // 由于通知收到的是redis key,value已经过期,无法收到,所以需要在key上标记业务数据。
        // 获取到失效的 key,进行取消订单业务处理
        String expiredKey = message.toString();
        System.out.println(expiredKey);
    }
}
经验分享 程序员 微信小程序 职场和发展