谷粒商城RabbitMQ设计思想详解:消息队列双重保险设计

前言

请添加图片描述
上来先放一张设计图,看这篇文章的前提是一定得写过或者了解这段业务,不然会看不懂,我下面将会给出我的理解,尽量让大家明白

设计思想

@Transactional
    @Override
    public SubmitOrderResponseVo submitOrder(OrderSubmitVo vo) {
        //前面的代码略过,只关注消息队列的入口        
          注意,这是整个mq系统的入口,调用了wmsFeignService.orderLockStock(lockVo)的时候就向stock.delay.queue这个延时队列(50min)里面添加了锁库存的消息,
          50min之后如果过期,此消息将会被自动路由(设计的时候就是这样设计的,是mq自动做的路由,不用写java代码)到死信队列stock.release.stock.queue中
          发送的类型是StockLockedTo对象,意味着这条消息将会被OrderCloseListener的第一个监听函数监听到,将会去解锁库存
         
          下面那个rabbitTemplate.convertAndSend("order-event-exchange","order.create.order",order.getOrder())
          是创建订单,订单将会在延时队列放30min直到付款或者取消
          如果取消或者30min后,这个消息将被自动路由(设计的时候就是这样设计的,是mq自动做的路由,不用写java代码)到死信队列order.release.order.queue中
          这个时候OrderCloseListener是监听着order.release.order.queue的,于是它将调用本类中的closeOrder()方法并将订单关闭这个消息路由到
          死信队列stock.release.stock.queue中,传输的是一个OrderTo对象,条消息将会被OrderCloseListener的第二个监听器接收到
         
          所以正确是玩法是:首先用户下好订单,如果在30min内没有支付或者取消了订单,那么证明这个订单是废单,因此需要把锁了的库存给解锁了,30min一到,
          OrderCloseListener的第二个监听器将会去解锁订单,50min后,还会有一道保险,也就是第一个监听器监听到50min过期的消息,尝试去解锁订单,形成双保险自动解锁。
          
        R r = wmsFeignService.orderLockStock(lockVo);
        if (r.getCode() == 0) {
            //锁定成功
            response.setOrder(order.getOrder());
            //TODO 订单创建成功,发送消息给MQ
            /**
             * 这是往时限为1分钟的延迟队列传输的信息,里面放着OrderEntity对象,一分钟后被送往死信队列order.release.order.queue
             **/
            rabbitTemplate.convertAndSend("order-event-exchange","order.create.order",order.getOrder());
            //删除购物车里的数据
            redisTemplate.delete(CART_PREFIX+memberResponseVo.getId());
            return response;
        } else {
            //锁定失败
            String msg = (String) r.get("msg");
            throw new NoStockException(msg);
        }
        //后面的代码略过
    }

大家对着我上面给出的一大段中文注释,自己去看看是不是这样的

我发现的细节

还有一个细节,如果有两个监听器一起监听一个队列,例如本项目:

@Slf4j
@RabbitListener(queues = "stock.release.stock.queue")
@Service
public class StockReleaseListener {

    @Autowired
    private WareSkuService wareSkuService;

    @RabbitHandler
    public void handleStockLockedRelease(StockLockedTo to, Message message, Channel channel) throws IOException {
        log.info("******50min了,我怕你20min前出问题没解锁到,这是第二道保险******");
        //具体代码
    }

    @RabbitHandler
    public void handleOrderCloseRelease(OrderTo orderTo, Message message, Channel channel) throws IOException {
        log.info("******30min了,你订单还没支付或者已经取消,我去解锁库存了******");
        //具体代码
    }

}

上面这两个代码我再次标明了这两个监听器的先后顺序以及作用,如果还懵的现在应该大概明白了吧

我一开始是不知道到底是哪个会先接受消息,后面发现这两个监听器不是去抢同一个消息的,而是
去拿自己对应的消息的,此话怎讲?

例如第一个监听器,它的第一个参数是StockLockedTo to,意味着如果当时给这个消息队列存的对象是StockLockedTo的话,将被这个监听器收到;

第二个监听器,它的第一个参数是OrderTo orderTo,意味着如果当时给这个消息队列存的对象是OrderTo 的话,将被这个监听器收到。

无论有几个监听器,他们只会取到他们应该取到的消息,所以放消息的时候要放好,取出来的时候也得取好,别放进去一个类,取出来用另一个类取,肯定是取不到的,会报错。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值