业务场景:
用户下单之后,在30分钟内如果不完成付款,订单自动取消,并且释放库存
使用技术:
Redis键空间通知(过期回调)用户下单之后将订单id作为key,任意值作为值存入redis中,给这条数据设置过期时间,也就是订单超时的时间
声明:
*本人菜鸟一枚,以下代码仅记录自己学习历程,不保证代码效果及性能,如有更好的方式,也欢迎讨论.
1.开启键空间通知
默认情况下,键空间通知是关闭的,需要在终端开启
redis-cli config set notify-keyspace-events KEA
KEA 参数意味着每一个可能的事件被启用
2.检查事件是否正常,终端输入
redis-cli --csv psubscribe '*'
psubscribe ‘*’ 意味着我们想要使用模式订阅所有事件
结果:
$ redis-cli --csv psubscribe '*'
Reading messages... (press Ctrl-C to quit)
"psubscribe","*",1
3.测试
新打开一个终端,输入
127.0.0.1:6379> set key1 value1
OK
在第一个终端,您将看到:
"psubscribe","*",1
"pmessage","*","__keyspace@0__:key1","set"
"pmessage","*","__keyevent@0__:set","key1
通知说明:
第一个事件意味着我们已成功订阅作为回复中第二个元素的通道。1表示我们当前订阅的频道数。
第二个事件是密钥空间通知。在密钥空间信道中,我们收到了事件的名称set作为消息。
第三个事件是关键事件通知。在keyevent频道中,我们收到了密钥的名称key1作为消息。
4.配置回调函数
a.首先在订单前,生成redis字符串,设置订单id,并有有效期
b.创建一个脚本文件,和django一起启动AutoCancelOrder.py
# 连接redis数据库
redis = StrictRedis(host='localhost', port=6379, decode_responses=True)
# 创建pubsub对象,该对象订阅一个频道并侦听新消息:
pubsub = redis.pubsub()
# 定义触发事件
def event_handler(msg):
print('Handler', msg)
print(msg['data'])
order_id = str(msg['data'])
# 获取订单对象
order = OrderInfo.objects.get(order_id=order_id)
# 判断用户是否已经付款
if str(order.status) == "1":
# 取消订单,更改订单状态
OrderInfo.objects.filter(order_id=order_id).update(status="6")
# 获取订单中的所有商品
goods = order.skus.all()
# 遍历商品
for good in goods:
# 获取订单中的商品数量
count = good.count
print(count)
# 获取sku商品
sku = good.sku
# 将库存重新增加到sku的stock中去
sku.stock += count
# 从销量中减去已经取消的数量
sku.sales -= count
sku.save()
#订阅redis键空间通知
pubsub.psubscribe(**{'__keyevent@0__:expired': event_handler})
# 死循环,不停的接收订阅的通知
while True:
message = pubsub.get_message()
if message:
print(message)
else:
time.sleep(0.01)
5.代码解释:
创建while True循环接收事件通知:
while True:
......
keyevent@0:expired’:
设定通知类型: keyspace、keyevent
设置事件类型: expired
选中数据库号: @0()
pubsub.psubscribe(**{'__keyevent@0__:expired': event_handler})
如果有数据,get_message()将读取并返回它。如果没有数据,则返回None。
从pubsub实例读取的每条消息都是一个包含以下键的字典:
键入下列之一:subscribe,unsubscribe,psubscribe,punsubscribe,message,pmessage
- channel:订阅的频道或发布消息的频道
- pattern:匹配已发布消息的通道的模式(除类型外在所有情况下均为Nonepmessage)
- data:消息数据