Browse Source

任务调度错过触发时间时的处理策略:
- 可能原因:服务重启;调度线程被阻塞,线程被耗尽;上次调度持续阻塞,下次调度被错过;
- 处理策略:
- 过期超10s:本地忽略,当前时间开始计算下次触发时间
- 过期超过5s:过期10s内:立即触发一次,当前时间开始计算下次触发时间

xuxueli 5 years ago
parent
commit
5c1f59323e

+ 3 - 3
doc/XXL-JOB官方文档.md

@@ -836,11 +836,11 @@ XXL-JOB调度模块默认采用并行机制,在多线程调度的情况下,
 XXL-JOB的每个调度任务虽然在调度模块是并行调度执行的,但是任务调度传递到任务模块的“执行器”确实串行执行的,同时支持任务终止。
 
 #### 5.4.6 过期处理策略
-任务调度错过触发时间:
+任务调度错过触发时间时的处理策略
 - 可能原因:服务重启;调度线程被阻塞,线程被耗尽;上次调度持续阻塞,下次调度被错过;
 - 处理策略:
-    - 过期5s内:立即触发一次,并计算下次触发时间;
-    - 过期超过5s:忽略过期触发,计算下次触发时间
+    - 过期超10s:本地忽略,当前时间开始计算下次触发时间
+    - 过期超过5s:过期10s内:立即触发一次当前时间开始计算下次触发时间
 
 
 #### 5.4.7 日志回调服务

+ 49 - 38
xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobScheduleHelper.java

@@ -1,8 +1,8 @@
 package com.xxl.job.admin.core.thread;
 
 import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
-import com.xxl.job.admin.core.model.XxlJobInfo;
 import com.xxl.job.admin.core.cron.CronExpression;
+import com.xxl.job.admin.core.model.XxlJobInfo;
 import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -58,7 +58,7 @@ public class JobScheduleHelper {
 
                         // tx start
 
-                        // 1、查询JOB:"下次调度30s内"  ( ...... -5 ... now ...... +30 ...... )
+                        // 1、查询JOB:"下次调度30s内"
                         long maxNextTime = System.currentTimeMillis() + 30000;
                         long nowTime = System.currentTimeMillis();
                         List<XxlJobInfo> scheduleList = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().scheduleJobQuery(maxNextTime);
@@ -66,35 +66,53 @@ public class JobScheduleHelper {
                             // 2、推送时间轮
                             for (XxlJobInfo jobInfo: scheduleList) {
 
-                                // 过期策略:过期=更新下次触发时间为当前、过期是否5s内=立即出发,否则忽略;
-                                if (jobInfo.getTriggerNextTime() < nowTime) {
-                                    jobInfo.setTriggerNextTime(nowTime);
-                                    if (jobInfo.getTriggerNextTime() < nowTime-10000) {
-                                        continue;
-                                    }
+                                // 时间轮刻度计算
+                                int ringSecond = -1;
+                                if (jobInfo.getTriggerNextTime() < nowTime - 10000) {   // 过期超10s:本地忽略,当前时间开始计算下次触发时间
+                                    ringSecond = -1;
+
+                                    jobInfo.setTriggerLastTime(jobInfo.getTriggerNextTime());
+                                    jobInfo.setTriggerNextTime(
+                                            new CronExpression(jobInfo.getJobCron())
+                                                    .getNextValidTimeAfter(new Date())
+                                                    .getTime()
+                                    );
+                                } else if (jobInfo.getTriggerNextTime() < nowTime) {    // 过期10s内:立即触发一次,当前时间开始计算下次触发时间
+                                    ringSecond = (int)((nowTime/1000)%60);
+
+                                    jobInfo.setTriggerLastTime(jobInfo.getTriggerNextTime());
+                                    jobInfo.setTriggerNextTime(
+                                            new CronExpression(jobInfo.getJobCron())
+                                                    .getNextValidTimeAfter(new Date())
+                                                    .getTime()
+                                    );
+                                } else {    // 未过期:正常触发,递增计算下次触发时间
+                                    ringSecond = (int)((jobInfo.getTriggerNextTime()/1000)%60);
+
+                                    jobInfo.setTriggerLastTime(jobInfo.getTriggerNextTime());
+                                    jobInfo.setTriggerNextTime(
+                                            new CronExpression(jobInfo.getJobCron())
+                                                    .getNextValidTimeAfter(new Date(jobInfo.getTriggerNextTime()))
+                                                    .getTime()
+                                    );
+                                }
+                                if (ringSecond == -1) {
+                                    continue;
                                 }
 
                                 // push async ring
-                                int second = (int)((jobInfo.getTriggerNextTime()/1000)%60);
-                                List<Integer> ringItemData = ringData.get(second);
+                                List<Integer> ringItemData = ringData.get(ringSecond);
                                 if (ringItemData == null) {
                                     ringItemData = new ArrayList<Integer>();
-                                    ringData.put(second, ringItemData);
+                                    ringData.put(ringSecond, ringItemData);
                                 }
                                 ringItemData.add(jobInfo.getId());
 
-                                logger.info(">>>>>>>>>>> xxl-job, push time-ring : " + second + " = " + Arrays.asList(ringItemData) );
+                                logger.info(">>>>>>>>>>> xxl-job, push time-ring : " + ringSecond + " = " + Arrays.asList(ringItemData) );
                             }
 
                             // 3、更新trigger信息
                             for (XxlJobInfo jobInfo: scheduleList) {
-                                // update
-                                jobInfo.setTriggerLastTime(jobInfo.getTriggerNextTime());
-                                jobInfo.setTriggerNextTime(
-                                        new CronExpression(jobInfo.getJobCron())
-                                                .getNextValidTimeAfter(new Date(jobInfo.getTriggerNextTime()))
-                                                .getTime()
-                                );
                                 XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().scheduleUpdate(jobInfo);
                             }
 
@@ -141,28 +159,22 @@ public class JobScheduleHelper {
                         List<Integer> ringItemData = new ArrayList<>();
                         int nowSecond = (int)((System.currentTimeMillis()/1000)%60);   // 避免处理耗时太长,跨过刻度;
                         if (lastSecond == -1) {
-                            if (ringData.containsKey(nowSecond)) {
-                                List<Integer> tmpData = ringData.remove(nowSecond);
-                                if (tmpData != null) {
-                                    ringItemData.addAll(tmpData);
-                                }
+                            lastSecond = (nowSecond+59)%60;
+                        }
+                        for (int i = 1; i <=60; i++) {
+                            int secondItem = (lastSecond+i)%60;
+
+                            List<Integer> tmpData = ringData.remove(secondItem);
+                            if (tmpData != null) {
+                                ringItemData.addAll(tmpData);
                             }
-                            lastSecond = nowSecond;
-                        } else {
-                            for (int i = 1; i <=60; i++) {
-                                int secondItem = (lastSecond+i)%60;
-
-                                List<Integer> tmpData = ringData.remove(secondItem);
-                                if (tmpData != null) {
-                                    ringItemData.addAll(tmpData);
-                                }
 
-                                if (secondItem == nowSecond) {
-                                    break;
-                                }
+                            if (secondItem == nowSecond) {
+                                break;
                             }
-                            lastSecond = nowSecond;
                         }
+                        lastSecond = nowSecond;
+
 
                         logger.info(">>>>>>>>>>> xxl-job, time-ring beat : " + nowSecond + " = " + Arrays.asList(ringItemData) );
                         if (ringItemData!=null && ringItemData.size()>0) {
@@ -171,7 +183,6 @@ public class JobScheduleHelper {
                                 // do trigger
                                 JobTriggerPoolHelper.trigger(jobId, TriggerTypeEnum.CRON, -1, null, null);
                             }
-
                             // clear
                             ringItemData.clear();
                         }