浏览代码

优化了分布式锁的使用,添加了合理的超时设置,避免任务超时导致任务列表溢出

codingliang 3 月之前
父节点
当前提交
77283c9f80

+ 13 - 2
src/main/java/com/sqx/modules/reconciliation/service/impl/PlatformBillServiceImpl.java

@@ -49,6 +49,7 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 import java.util.function.ToIntFunction;
 import java.util.stream.Collectors;
@@ -82,8 +83,13 @@ public class PlatformBillServiceImpl extends ServiceImpl<PlatformBillMapper, Pla
     @Override
     public void generatePlatformBill(LocalDate date, boolean cover) {
         RLock lock = redissonClient.getLock(RedisKey.PLATFORM_BILL_LOCK);
-        lock.lock();
+        boolean locked = false;
         try {
+            locked = lock.tryLock(0, 120, TimeUnit.SECONDS);
+            if (!locked) {
+                log.info("未获取到对账锁,跳过本次执行");
+                return;
+            }
             // 判断有无当天数据,然后根据策略觉得是否执行覆盖数据还是直接退出
             LambdaQueryWrapper<PlatformBill> wrapper = Wrappers.lambdaQuery();
             wrapper.eq(PlatformBill::getDayId, date);
@@ -112,8 +118,13 @@ public class PlatformBillServiceImpl extends ServiceImpl<PlatformBillMapper, Pla
                 transactionManager.rollback(status);
                 throw new SqxException("账单数据保存失败", e);
             }
+        } catch (Exception e) {
+            log.error("生成对账数据失败", e);
+            throw new SqxException(e.getMessage(), e);
         } finally {
-            lock.unlock();
+            if (locked && lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
         }
     }
 

+ 3 - 3
src/main/java/com/sqx/scheduler/config/ScheduledConfig.java

@@ -23,9 +23,9 @@ public class ScheduledConfig implements AsyncConfigurer {
     @Override
     public Executor getAsyncExecutor() {
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
-        executor.setCorePoolSize(10);
-        executor.setMaxPoolSize(20);
-        executor.setQueueCapacity(150);
+        executor.setCorePoolSize(20);
+        executor.setMaxPoolSize(40);
+        executor.setQueueCapacity(200);
         executor.setKeepAliveSeconds(60);
         executor.setThreadNamePrefix("wm-task-");
         executor.initialize();

+ 11 - 2
src/main/java/com/sqx/scheduler/coupon/CouponScheduler.java

@@ -11,6 +11,8 @@ import org.springframework.scheduling.annotation.Async;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * 优惠券定时任务
  *
@@ -33,15 +35,22 @@ public class CouponScheduler {
     @Scheduled(cron = "0 */1 * * * ?", zone = "Asia/Shanghai")
     public void couponEnd(){
         RLock lock = redissonClient.getLock(SchedulerLock.COUPON_OF_USER_EXPIRATION_LOCK);
-        lock.lock();
+        boolean locked = false;
         try {
+            locked = lock.tryLock(0, 120, TimeUnit.SECONDS);
+            if (!locked) {
+                log.info("未获取到用户优惠券自动过期锁,跳过本次执行");
+                return;
+            }
             log.info("用户优惠券自动过期任务运行");
             tbCouponUserService.updateExpiration();
             log.info("用户优惠券自动过期任务运行成功");
         } catch (Exception e) {
             log.error("用户优惠券自动过期任务运行失败,【{}】", e);
         } finally {
-            lock.unlock();
+            if (locked && lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
         }
 
     }

+ 10 - 2
src/main/java/com/sqx/scheduler/indent/IndentScheduler.java

@@ -24,6 +24,7 @@ import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * 跑腿订单定时任务
@@ -52,8 +53,13 @@ public class IndentScheduler {
     @Scheduled(cron = "0 * * * * ?", zone = "Asia/Shanghai")
     public void autoSendOrder(){
         RLock lock = redissonClient.getLock(SchedulerLock.INDENT_AUTO_PUSH_LOCK);
-        lock.lock();
+        boolean locked = false;
         try {
+            locked = lock.tryLock(0, 120, TimeUnit.SECONDS);
+            if (!locked) {
+                log.info("未获取到自动给骑手推单锁,跳过本次执行");
+                return;
+            }
             log.info("自动给骑手推单任务开始运行");
             CommonInfo three = commonInfoService.findOne(304);
             if("是".equals(three.getValue())){
@@ -120,7 +126,9 @@ public class IndentScheduler {
         } catch (Exception e) {
             log.error("自动给骑手推单任务开始运行失败,【{}】", e);
         } finally {
-            lock.unlock();
+            if (locked && lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
         }
     }
 

+ 39 - 14
src/main/java/com/sqx/scheduler/order/OrderScheduler.java

@@ -68,8 +68,15 @@ public class OrderScheduler {
     @Scheduled(cron = "0 */5 * * * ?")
     public void reservationAutoReceivingOrder() {
         RLock lock = redissonClient.getLock(SchedulerLock.ORDER_OF_RESERVATION_AUTO_RECEIVING_LOCK);
-        lock.lock();
+        boolean locked = false;
         try {
+            locked = lock.tryLock(0, 120, TimeUnit.SECONDS);
+            if (!locked) {
+                // 获取不到锁,说明有其他实例正在执行此任务
+                log.info("未获取到预约订单自动接单锁,跳过本次执行");
+                return;
+            }
+
             log.info("预约订单自动接单任务开始运行");
             List<Long> orderIds = orderService.getCurWaitReceivingOrderIds();
             if (CollUtil.isEmpty(orderIds)) {
@@ -100,7 +107,9 @@ public class OrderScheduler {
         } catch (Exception e) {
             log.error("预约订单自动接单任务运行失败失败原因:{}", e.getMessage());
         } finally {
-            lock.unlock();
+            if (locked && lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
         }
     }
 
@@ -153,13 +162,19 @@ public class OrderScheduler {
     @Scheduled(cron = "45 */1 * * * ?")
     public void autoFinishOrder() {
         RLock lock = redissonClient.getLock(SchedulerLock.ORDER_OF_WAIT_DELIVERY_AUTO_FINISH_LOCK);
-        lock.lock();
+        boolean locked = false;
         try {
+            locked = lock.tryLock(0, 120, TimeUnit.SECONDS);
+            if (!locked) {
+                log.info("未获取到自动完成订单锁,跳过本次执行");
+                return;
+            }
+
             log.info("自动完成订单任务开始运行");
             CommonInfo one = commonInfoService.findOne(268);
             DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
 
-//            查询三大运营商的店铺
+            // 查询三大运营商的店铺
             List<Long> shopList = new ArrayList<>();
             QueryWrapper<ShopType> wrapperShopType = new QueryWrapper<>();
             wrapperShopType.eq("shop_type_name", "三大运营商");
@@ -197,7 +212,9 @@ public class OrderScheduler {
         } catch (Exception e) {
             log.info("自动完成订单任务运行异常,异常", e);
         } finally {
-            lock.unlock();
+            if (locked && lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
         }
     }
 
@@ -209,8 +226,15 @@ public class OrderScheduler {
     @Scheduled(cron = "0 */3 * * * ?")
     public void changeTimeOutOrder() {
         RLock lock = redissonClient.getLock(SchedulerLock.TIME_OUT_LOCK);
-        lock.lock();
+        boolean locked = false;
         try {
+            locked = lock.tryLock(0, 300, TimeUnit.SECONDS);
+            if (!locked) {
+                // 获取不到锁,说明有其他实例正在执行此任务
+                log.info("未获取到超时订单处理锁,跳过本次执行");
+                return;
+            }
+
             log.info("超时订单自动取消任务开始运行");
             // 加5分钟在前端强制取消前执行 ??
             long time = new Date().getTime() + 5*60*1000;
@@ -276,7 +300,9 @@ public class OrderScheduler {
             log.error("超时订单自动取消任务运行失败失败原因:{}", e.getMessage());
             e.printStackTrace();
         } finally {
-            lock.unlock();
+            if (locked && lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
         }
     }
 
@@ -287,13 +313,12 @@ public class OrderScheduler {
      @Async
      @Scheduled(cron = "0 0 1 * * ?")
     public void updateShopSales() {
-        RLock lock = null;
+        RLock lock = redissonClient.getLock(SchedulerLock.UPDATE_SHOP_SALES_LOCK);
+        boolean locked = false;
         try {
-            // 尝试获取锁,最多等待0秒(即立即返回),锁的过期时间为2分钟
-            lock = redissonClient.getLock(SchedulerLock.UPDATE_SHOP_SALES_LOCK);
-            boolean isLocked = lock.tryLock(0, 2, TimeUnit.MINUTES);
-            if (!isLocked) {
-                log.info("更新店铺销量任务:当前有其他服务实例正在执行,本次跳过");
+            locked = lock.tryLock(0, 60, TimeUnit.SECONDS);
+            if (!locked) {
+                log.info("更新店铺销量任务:获取锁失败,本次跳过");
                 return;
             }
             log.info("更新店铺销量任务开始运行");
@@ -303,7 +328,7 @@ public class OrderScheduler {
         } catch (Exception e) {
             log.error("更新店铺销量任务运行失败,失败原因:{}", e.getMessage());
         } finally {
-            if (lock != null && lock.isHeldByCurrentThread()) {
+            if (locked && lock.isHeldByCurrentThread()) {
                 lock.unlock();
             }
         }

+ 0 - 29
src/main/java/com/sqx/scheduler/reconciliation/BillsScheduler.java

@@ -23,35 +23,6 @@ public class BillsScheduler {
     private final PlatformBillService platformBillService;
 
     /**
-     * 将所有超过失效时间的优惠券改为失效状态
-     * 每填0点2分30秒执行一次
-     */
-//     @Async
-//     @Scheduled(cron = "30 2 0 * * ?", zone = "Asia/Shanghai")
-// //    @Scheduled(cron = "30 * * * * ?", zone = "Asia/Shanghai")
-//     public void insertPlatformBill(){
-//         int errorCount = 0 ;
-//         log.info("开始统计对账数据");
-//         while (errorCount<3){
-//             try {
-//                 int count =platformBillService.insertPlatformBill();
-//                 if(count!=0){
-//                     break;
-//                 }
-//             } catch (Exception e) {
-//                 log.error("统计对账数据异常:{}", e.getMessage());
-//                 errorCount++;
-//                 try {
-//                     Thread.sleep(10000);
-//                 } catch (InterruptedException ex) {
-//                     throw new RuntimeException(ex);
-//                 }
-//             }
-//         }
-//         log.info("统计对账数据结束");
-//     }
-
-    /**
      * 定时生成对账单
      *    每天的2点30分、40分、50分执行一次
      */