Browse Source

通过延时队列实现检查订单是否已经超期,自动取消订单的功能

朱洪锦 6 years ago
parent
commit
e95948bfa3

+ 27 - 27
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/job/OrderJob.java

@@ -40,33 +40,33 @@ public class OrderJob {
      * TODO
      * 注意,因为是相隔半小时检查,因此导致订单真正超时时间是 [LITEMALL_ORDER_UNPAID, 30 + LITEMALL_ORDER_UNPAID]
      */
-    @Scheduled(fixedDelay = 30 * 60 * 1000)
-    @Transactional(rollbackFor = Exception.class)
-    public void checkOrderUnpaid() {
-        logger.info("系统开启任务检查订单是否已经超期自动取消订单");
-
-        List<LitemallOrder> orderList = orderService.queryUnpaid(SystemConfig.getOrderUnpaid());
-        for (LitemallOrder order : orderList) {
-            // 设置订单已取消状态
-            order.setOrderStatus(OrderUtil.STATUS_AUTO_CANCEL);
-            order.setEndTime(LocalDateTime.now());
-            if (orderService.updateWithOptimisticLocker(order) == 0) {
-                throw new RuntimeException("更新数据已失效");
-            }
-
-            // 商品货品数量增加
-            Integer orderId = order.getId();
-            List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
-            for (LitemallOrderGoods orderGoods : orderGoodsList) {
-                Integer productId = orderGoods.getProductId();
-                Short number = orderGoods.getNumber();
-                if (productService.addStock(productId, number) == 0) {
-                    throw new RuntimeException("商品货品库存增加失败");
-                }
-            }
-            logger.info("订单 ID" + order.getId() + " 已经超期自动取消订单");
-        }
-    }
+//    @Scheduled(fixedDelay = 30 * 60 * 1000)
+//    @Transactional(rollbackFor = Exception.class)
+//    public void checkOrderUnpaid() {
+//        logger.info("系统开启任务检查订单是否已经超期自动取消订单");
+//
+//        List<LitemallOrder> orderList = orderService.queryUnpaid(SystemConfig.getOrderUnpaid());
+//        for (LitemallOrder order : orderList) {
+//            // 设置订单已取消状态
+//            order.setOrderStatus(OrderUtil.STATUS_AUTO_CANCEL);
+//            order.setEndTime(LocalDateTime.now());
+//            if (orderService.updateWithOptimisticLocker(order) == 0) {
+//                throw new RuntimeException("更新数据已失效");
+//            }
+//
+//            // 商品货品数量增加
+//            Integer orderId = order.getId();
+//            List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
+//            for (LitemallOrderGoods orderGoods : orderGoodsList) {
+//                Integer productId = orderGoods.getProductId();
+//                Short number = orderGoods.getNumber();
+//                if (productService.addStock(productId, number) == 0) {
+//                    throw new RuntimeException("商品货品库存增加失败");
+//                }
+//            }
+//            logger.info("订单 ID" + order.getId() + " 已经超期自动取消订单");
+//        }
+//    }
 
     /**
      * 自动确认订单

+ 3 - 0
litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallOrderService.java

@@ -5,6 +5,7 @@ import org.linlinjava.litemall.db.dao.LitemallOrderMapper;
 import org.linlinjava.litemall.db.dao.OrderMapper;
 import org.linlinjava.litemall.db.domain.LitemallOrder;
 import org.linlinjava.litemall.db.domain.LitemallOrderExample;
+import org.linlinjava.litemall.db.task.OrderDelayedTaskManager;
 import org.linlinjava.litemall.db.util.OrderUtil;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
@@ -28,6 +29,8 @@ public class LitemallOrderService {
     public int add(LitemallOrder order) {
         order.setAddTime(LocalDateTime.now());
         order.setUpdateTime(LocalDateTime.now());
+        OrderDelayedTaskManager manager = OrderDelayedTaskManager.getInstance();
+        manager.putQueue(order);
         return litemallOrderMapper.insertSelective(order);
     }
 

+ 55 - 0
litemall-db/src/main/java/org/linlinjava/litemall/db/task/OrderDelayedTask.java

@@ -0,0 +1,55 @@
+package org.linlinjava.litemall.db.task;
+
+import org.linlinjava.litemall.db.domain.LitemallOrder;
+
+import java.time.ZoneOffset;
+import java.util.concurrent.Delayed;
+import java.util.concurrent.TimeUnit;
+
+public class OrderDelayedTask implements Delayed {
+
+
+    private LitemallOrder order;
+    /**
+     * 延时时间 单位 timeunit.milliseconds
+     **/
+    private long timeout;
+    private long exprire;
+
+    public OrderDelayedTask(LitemallOrder order, long timeout) {
+        this.order = order;
+        this.timeout = timeout;
+        this.exprire = order.getAddTime().toInstant(ZoneOffset.of("+8")).toEpochMilli() + timeout;
+    }
+
+    public LitemallOrder getOrder() {
+        return order;
+    }
+
+    @Override
+    public long getDelay(TimeUnit unit) {
+        return unit.convert(exprire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
+    }
+
+    @Override
+    public int compareTo(Delayed o) {
+        OrderDelayedTask other = (OrderDelayedTask) o;
+        long diff = order.getAddTime().toInstant(ZoneOffset.of("+8")).toEpochMilli()
+                - other.getOrder().getAddTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
+        if (diff > 0) {
+            return 1;
+        } else if (diff < 0) {
+            return -1;
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "OrderDelayedTask{" +
+                "order=" + order +
+                ", timeout=" + timeout +
+                '}';
+    }
+}

+ 103 - 0
litemall-db/src/main/java/org/linlinjava/litemall/db/task/OrderDelayedTaskManager.java

@@ -0,0 +1,103 @@
+package org.linlinjava.litemall.db.task;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.linlinjava.litemall.db.domain.LitemallOrder;
+import org.linlinjava.litemall.db.domain.LitemallOrderGoods;
+import org.linlinjava.litemall.db.service.LitemallGoodsProductService;
+import org.linlinjava.litemall.db.service.LitemallOrderGoodsService;
+import org.linlinjava.litemall.db.service.LitemallOrderService;
+import org.linlinjava.litemall.db.util.OrderUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.concurrent.DelayQueue;
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class OrderDelayedTaskManager {
+
+    private static final Log log = LogFactory.getLog(OrderDelayedTaskManager.class);
+
+    @Autowired
+    private LitemallOrderGoodsService orderGoodsService;
+    @Autowired
+    private LitemallOrderService orderService;
+    @Autowired
+    private LitemallGoodsProductService productService;
+
+    private DelayQueue<OrderDelayedTask> queue;
+
+    // 守护线程
+    private Thread daemonThread;
+
+
+    private static OrderDelayedTaskManager instance = new OrderDelayedTaskManager();
+
+    private OrderDelayedTaskManager() {
+        queue = new DelayQueue<>();
+        init();
+    }
+
+    public static OrderDelayedTaskManager getInstance() {
+        return instance;
+    }
+
+    /**
+     * 初始化
+     */
+    public void init() {
+        daemonThread = new Thread(() -> execute());
+        daemonThread.setName("DelayQueueMonitor");
+        daemonThread.start();
+    }
+
+
+    public void execute() {
+        while (true) {
+            log.info("当前延时队列的任务数量:" + queue.size());
+            try {
+                OrderDelayedTask task = queue.take();
+                if (null != task) {
+                    LitemallOrder order = task.getOrder();
+                    if (null == order) {
+                        continue;
+                    }
+                    // 设置订单已取消状态
+                    order.setOrderStatus(OrderUtil.STATUS_AUTO_CANCEL);
+                    order.setEndTime(LocalDateTime.now());
+                    if (orderService.updateWithOptimisticLocker(order) == 0) {
+                        throw new RuntimeException("更新数据已失效");
+                    }
+                    // 商品货品数量增加
+                    Integer orderId = order.getId();
+                    List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
+                    for (LitemallOrderGoods orderGoods : orderGoodsList) {
+                        Integer productId = orderGoods.getProductId();
+                        Short number = orderGoods.getNumber();
+                        if (productService.addStock(productId, number) == 0) {
+                            throw new RuntimeException("商品货品库存增加失败");
+                        }
+                    }
+                    log.info("订单 ID" + order.getId() + " 已经超期自动取消订单");
+                    log.info("end:" + LocalDateTime.now());
+                }
+
+            } catch (InterruptedException e) {
+                log.error("获取延时任务失败!", e);
+            }
+        }
+    }
+
+    public void putQueue(LitemallOrder order) {
+        OrderDelayedTask task = new OrderDelayedTask(order, TimeUnit.MINUTES.toMillis(30));
+        queue.put(task);
+    }
+
+    public void removeQueue(OrderDelayedTask task) {
+        queue.remove(task);
+    }
+
+}