栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

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

谷粒商城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
            
            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 的话,将被这个监听器收到。

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/674190.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号