SpringBoot监听redis键过期事件,实现订单超时关闭
SpringBoot监听redis键过期事件,实现订单超时关闭
场景
订单超时关闭,客户下单时未支付,超过一段时间会自动将订单修改为已关闭,不允许再次支付。类似的场景还有很多,只要用到有过期概念的都可以设计成该做法。
通常做法
- 通过定时任务每隔一段时间检查是否有超时订单,修改订单的状态,释放库存等等。
- 缺点:后台定时任务运行频繁,涉及订单操作业务比较复杂,增加服务器压力
思路
- 单机部署可以使用java8里面的DelayQueue延时队列,对超时的订单执行取消操作,同时缺点也存在,比如服务器宕机,那保存在内存的订单延时队列就被清空,对业务影响也比较大,建议和定时器结合使用。
- 使用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); } }