商城订单失效

前言:说一下这里做的订单到期,用户还未支付,对订单进行失效处理

线上总共有4台机。有一台是job机,再说下,我们日常商城订单量并不算多,也就几百单, 所以这里是一个简单的订单失效处理

 

public class App2 {

    private final static Logger LOGGER = LoggerFactory.getLogger(App2.class);


    private final LinkedBlockingQueue queue = new LinkedBlockingQueue();

        private final Timer timer = new Timer("ScheduleOrderOutTimerThread");
        /**
         * 首次处理的的状态标识
         */
        private AtomicBoolean delayedFlag = new AtomicBoolean(false);

        private static final long DELAY_FOR_A_PERIOD = 4000L;


        /**
         * 描述:处理过期的订单
         *
         * @return
         * @author: miaomiao
         * @date: 2019-05-21 10:37
         */
        @Override
        public JSONObject handleOutTimeOrder(String params) {
            JSONObject json = new JSONObject();
            json.put("result", "ok");
            json.put("msg", "调用成功");

            //订单超时时间,这个时间是限制用户停止支付
            Integer outTime = config.getShopTimeOutMinute();
            //过期多久时间内置为取消,时间单位是分钟,这个是订单停止支付,多少时间之后置为失效,怕用户这段时间期间内再第三方进行订单支付
            Integer min = config.getOutTimeRangeCancel();

            OrderBy orderBy = new OrderBy("create_time", OrderBy.ASC);

            ShopOrderQuery query = new ShopOrderQuery();
            query.setIncludeStatus(Arrays.asList(ShopOrderStatusEnum.WAIT_PAY.getStatus()));
            query.setOrderBy(orderBy);

            //根据时间正序查询 用户未支付的订单
            List orderList = shopOrderService.query(query);
            if (CollectionUtils.isNotEmpty(orderList)) {
                for (ShopOrder shopOrder : orderList) {
                    try {
                        queue.put(shopOrder);

                    } catch (InterruptedException e) {
                        LOGGER.error("放入queue异常", e);
                    }
                }

                //delayedFlag 的作用,限制只有一个线程在进行队列里订单的失效处理
                if (!delayedFlag.get()) {
                    //取 队列的头部 订单,第一个订单是最早的订单
                    ShopOrder shopOrder = queue.poll();
                    if (shopOrder != null) {
                        Calendar cal = Calendar.getInstance();
                        cal.setTime(shopOrder.getCreateTime());
                        cal.add(Calendar.MINUTE, outTime + min);
                        /**
                         * 一个定时线程去延时启动,执行失效处理
                         * 所以这里有个可能,这个订单用户正在进行支付
                         * 所以这里是当前时间+ (之前配置文件里取出来的 outTime) 过期时间。
                         */
                        this.timer.schedule(new DeliverDelayedMessageTimerTask(shopOrder, 0), cal.getTime());
                        delayedFlag.compareAndSet(false, true);
                    } else {
                        delayedFlag.compareAndSet(true, false);
                        json.put("msg", "暂无订单数据");
                    }
                }

            } else {
                json.put("result", "ok");
                json.put("msg", "暂无订单数据");
            }

            return json;
        }

        class DeliverDelayedMessageTimerTask extends TimerTask {

            private ShopOrder shopOrder;

            /**
             * 一次任务的失败次数
             */
            private AtomicInteger errorNums;

            public DeliverDelayedMessageTimerTask(ShopOrder shopOrder, int errorNums) {
                this.shopOrder = shopOrder;
                this.errorNums = new AtomicInteger(errorNums);
            }

            @Override
            public void run() {
                try {
                    this.executeOnTimeup();
                } catch (Exception e) {
                    LOGGER.error("ScheduleMessageService, executeOnTimeup exception,prams:" + shopOrder.toString(), e);
                    //默认重试5次
                    if (errorNums.incrementAndGet() < 5) {
                        ShopOrderDelayManagerImpl.this.timer.schedule(new DeliverDelayedMessageTimerTask(this.shopOrder, errorNums.get()), DELAY_FOR_A_PERIOD);
                    } else {
                        delayedFlag.compareAndSet(true, false);
                    }
                }
            }

            public void executeOnTimeup() throws Exception {
                while (true) {
                    LOGGER.info("shopOrder进行消息处理:"+this.shopOrder);
                    if (this.shopOrder == null) {
                        if(take()){
                            continue;
                        }else{
                            break;
                        }
                    }
                    //去判断订单的状态,如果订单不是等待状态 || 处理中状态,则拿取下一个订单。
                    if(this.shopOrder.getStatus() != ShopOrderStatusEnum.WAIT_PAY.getStatus() &&
                            this.shopOrder.getStatus() !=ShopOrderStatusEnum.PROCESS_PAY.getStatus() ){
                        if(take()){
                            continue;
                        }else{
                            //退出本次线程
                            break;
                        }
                    }
                    //1。去第三方核对订单是否支付

                    //2、回滚份额是首步,就算失败了,继续延迟,然后更新订单
                     

                    //3、回滚积分
                     

                    //4、回滚订单
                     

                    this.shopOrder =null;
                }
            }

            /**
             * 拿取商品
             * @return
             */
            private boolean take( ){
                //过期多久时间内置为取消,时间单位是分钟
                Integer min = config.getOutTimeRangeCancel();
                //订单超时时间
                Integer outTime = config.getShopTimeOutMinute();
                ShopOrder shopOrder = queue.poll();
                if (shopOrder != null) {
                    Calendar cal = Calendar.getInstance();
                    cal.setTime(shopOrder.getCreateTime());
                    cal.add(Calendar.MINUTE, outTime + min);

                    //现在的时间 > 订单超过处理时间
                    if(System.currentTimeMillis()>cal.getTimeInMillis() ){
                        this.shopOrder = shopOrder;
                        this.errorNums = new AtomicInteger(0);
                        return true;
                    } else{
                        ShopOrderDelayManagerImpl.this.timer.schedule(new DeliverDelayedMessageTimerTask(shopOrder, 0), cal.getTime());
                        return false;
                    }
                } else {
                    delayedFlag.compareAndSet(true, false);
                    return false;
                }
            }


        }

}

1、一台机job去定时跑逾期订单

2、会捞取待付款的订单,把订单放入 LinkedBlockingQueue queue 

3、delayedFlag代表只有一个线程去处理逾期订单, delayedFlag:true,已经有订单在处理中,false代表线程空闲,支持开启一个线程去处理

4、然后会启动一个延时线程去处理该订单,延时时间设置为:当前时间+订单过期时间+过期延迟时间

5、去处理订单的时候会有个时间判断,判断是否到达时间去处理订单。时间未达到的话,会启动一个延时线程去处理,然后结束本线程。时间达到的话,就直接处理该订单

6、判断订单是否处于未支付状态

7、判断订单在第三方是否付款

8、处理订单逾期业务

9、把this.shopOrder置为null、再次走循环

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(自己的业务)