基于主动+被动组合方式实现订单的关闭

背景

订单创建成功之后,超过一定时间不支付,就需要关闭订单,这里方案有很多,比如用 MQ、定时任务、Redis 等等。
 

我们选择了一种相对轻量并且也比较可靠的方案,那就是 XXL-JOB 定时任务,并且为了减少 XXL-JOB 关单的延迟问题,我们同时引入了被动关单的逻辑。


 

被动关单

所谓被动关单,就是说当用户想要操作这个订单的时候,我们去检查下是不是已经超时了,如果超时了,并且状态还不是已关闭的话,那就执行一次关单操作。

这种被动关单,我们在两个地方都加了:

  • 1、用户对订单支付时
  • 2、用户查看订单详情时

订单支付时关单

用户可以通过订单列表唤起收银台进行支付,在支付接口中,我们进行了判断:

@PostMapping("/pay")
public Result<PayOrderVO> pay(@Valid @RequestBody PayParam payParam) {
    String userId = (String) StpUtil.getLoginId();
    SingleResponse<TradeOrderVO> singleResponse = orderFacadeService.getTradeOrder(payParam.getOrderId(), userId);

    TradeOrderVO tradeOrderVO = singleResponse.getData();

    if (tradeOrderVO == null) {
        throw new TradeException(TradeErrorCode.GOODS_NOT_EXIST);
    }

    if (tradeOrderVO.getOrderState() != TradeOrderState.CONFIRM) {
        throw new TradeException(TradeErrorCode.ORDER_IS_CANNOT_PAY);
    }

    if (tradeOrderVO.getTimeout()) {
        doAsyncTimeoutOrder(tradeOrderVO);
        throw new TradeException(TradeErrorCode.ORDER_IS_CANNOT_PAY);
    }

    //支付逻辑省略
}

这里,针对状态为 CONFIRM 并且已经达到了关单时间的订单,进行一次异步的订单关闭操作。异步关单逻辑如下:

private void doAsyncTimeoutOrder(TradeOrderVO tradeOrderVO) {
    if (tradeOrderVO.getOrderState() != TradeOrderState.CLOSED) {
        Thread.ofVirtual().start(() -> {
            OrderTimeoutRequest cancelRequest = new OrderTimeoutRequest();
            cancelRequest.setOperatorType(PLATFORM);
            cancelRequest.setOperator(PLATFORM.getDesc());
            cancelRequest.setOrderId(tradeOrderVO.getOrderId());
            cancelRequest.setOperateTime(new Date());
            cancelRequest.setIdentifier(UUID.randomUUID().toString());
            orderFacadeService.timeout(cancelRequest);
        });
    }
}

这里用了虚拟线程,发起关单操作,这里通过异步实现,不阻塞主线程,主线程直接返回告诉用户订单状态无法支付即可,等他再次刷新时,异步线程执行完了,这个订单也就被关闭了。

用户查看订单详情时关单

除了在列表页的支付发起我们会进行被动关单,还会在用户主动查看订单详情的时候进行这个关单动作。

@GetMapping("/orderDetail")
public Result<TradeOrderVO> orderDetail(@NotNull String orderId) {
    String userId = (String) StpUtil.getLoginId();
    SingleResponse<TradeOrderVO> singleResponse = orderFacadeService.getTradeOrder(orderId, userId);
    if (singleResponse.getSuccess()) {
        TradeOrderVO tradeOrderVO = singleResponse.getData();
        if (tradeOrderVO.getTimeout() && tradeOrderVO.getOrderState() == TradeOrderState.CONFIRM) {
            //如果订单已经超时,并且尚未关闭,则执行一次关单后再返回数据
            OrderTimeoutRequest cancelRequest = new OrderTimeoutRequest();
            cancelRequest.setOperatorType(PLATFORM);
            cancelRequest.setOperator(PLATFORM.getDesc());
            cancelRequest.setOrderId(tradeOrderVO.getOrderId());
            cancelRequest.setOperateTime(new Date());
            cancelRequest.setIdentifier(UUID.randomUUID().toString());
            orderFacadeService.timeout(cancelRequest);
            singleResponse = orderFacadeService.getTradeOrder(orderId, userId);
        }
        return Result.success(singleResponse.getData());
    } else {
        return Result.error(singleResponse.getResponseCode(), singleResponse.getResponseMessage());
    }
}

这里。同样是针对状态为 CONFIRM 并且已经达到了关单时间的订单,进行一次同步的订单关闭操作。

这里为啥就不是异步而是同步了呢?因为这里需要在前台准确的返回最新的订单信息,所以需要同步执行。

主动关单

除了以上2个被动关单场景外,我们还使用XXL-JOB定义了定时任务进行定时执行,进行批量的订单超时关闭,之后会详细说明。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

埃泽漫笔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值