Browse Source

路由策略新增 "忙碌转移" 模式:按照顺序依次进行空闲检测,第一个空闲检测成功的机器选定为目标执行器并发起调度;

xuxueli 7 years ago
parent
commit
7e35088764

+ 2 - 1
README.md

@@ -857,6 +857,7 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
 - 1、任务Cron更新逻辑优化,改为rescheduleJob,同时防止cron重复设置;
 - 2、优化:API回调服务失败状态码优化,方便问题排查;
 - 3、XxlJobLogger的日志多参数支持;
+- 4、路由策略新增 "忙碌转移" 模式:按照顺序依次进行空闲检测,第一个空闲检测成功的机器选定为目标执行器并发起调度;
 
 #### TODO LIST
 - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限;
@@ -868,7 +869,7 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
 - 7、调度任务优先级;
 - 8、移除quartz依赖,重写调度模块:新增或恢复任务时将下次执行记录插入delayqueue,调度中心集群竞争分布式锁,成功节点批量加载到期delayqueue数据,批量执行。
 - 9、任务线程轮空30次后自动销毁,降低低频任务的无效线程消耗。
-- 10、路由策略新增 "忙碌转移" 模式,发现执行器运行中,主动转移下一个执行器调度任务;
+
 
 ## 七、其他
 

+ 65 - 59
xxl-job-admin/src/main/java/com/xxl/job/admin/core/jobbean/RemoteHttpJobBean.java

@@ -114,76 +114,82 @@ public class RemoteHttpJobBean extends QuartzJobBean {
 			return new ReturnT<String>(ReturnT.FAIL_CODE, triggerSb.toString());
 		}
 
-		// trigger remote executor
-		if (addressList.size() == 1) {
-			String address = addressList.get(0);
-			jobLog.setExecutorAddress(address);
-
-			ReturnT<String> runResult = runExecutor(triggerParam, address);
-			triggerSb.append("<br>----------------------<br>").append(runResult.getMsg());
+		// executor route strategy
+		ExecutorRouteStrategyEnum executorRouteStrategyEnum = ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null);
+		if (executorRouteStrategyEnum == null) {
+			triggerSb.append("<br>----------------------<br>").append("调度失败:").append("执行器路由策略为空");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, triggerSb.toString());
+		}
+		triggerSb.append("<br>路由策略:").append(executorRouteStrategyEnum.name() + "-" + executorRouteStrategyEnum.getTitle());
 
-			return new ReturnT<String>(runResult.getCode(), triggerSb.toString());
-		} else {
-			// executor route strategy
-			ExecutorRouteStrategyEnum executorRouteStrategyEnum = ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null);
-			triggerSb.append("<br>路由策略:").append(executorRouteStrategyEnum!=null?(executorRouteStrategyEnum.name() + "-" + executorRouteStrategyEnum.getTitle()):null);
-			if (executorRouteStrategyEnum == null) {
-				triggerSb.append("<br>----------------------<br>").append("调度失败:").append("执行器路由策略为空");
-				return new ReturnT<String>(ReturnT.FAIL_CODE, triggerSb.toString());
-			}
+		// trigger remote executor
+		if (executorRouteStrategyEnum == ExecutorRouteStrategyEnum.FAILOVER) {
+			for (String address : addressList) {
+				// beat
+				ReturnT<String> beatResult = null;
+				try {
+					ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, address).getObject();
+					beatResult = executorBiz.beat();
+				} catch (Exception e) {
+					logger.error("", e);
+					beatResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
+				}
+				triggerSb.append("<br>----------------------<br>")
+						.append("心跳检测:")
+						.append("<br>address:").append(address)
+						.append("<br>code:").append(beatResult.getCode())
+						.append("<br>msg:").append(beatResult.getMsg());
 
-			if (executorRouteStrategyEnum != ExecutorRouteStrategyEnum.FAILOVER) {
-				// get address
-				String address = executorRouteStrategyEnum.getRouter().route(jobInfo.getId(), addressList);
-				jobLog.setExecutorAddress(address);
+				// beat success
+				if (beatResult.getCode() == ReturnT.SUCCESS_CODE) {
+					jobLog.setExecutorAddress(address);
 
-				// run
-				ReturnT<String> runResult = runExecutor(triggerParam, address);
-				triggerSb.append("<br>----------------------<br>").append(runResult.getMsg());
+					ReturnT<String> runResult = runExecutor(triggerParam, address);
+					triggerSb.append("<br>----------------------<br>").append(runResult.getMsg());
 
-				return new ReturnT<String>(runResult.getCode(), triggerSb.toString());
-			} else {
-				for (String address : addressList) {
-					// beat
-					ReturnT<String> beatResult = beatExecutor(address);
-					triggerSb.append("<br>----------------------<br>").append(beatResult.getMsg());
+					return new ReturnT<String>(runResult.getCode(), triggerSb.toString());
+				}
+			}
+			return new ReturnT<String>(ReturnT.FAIL_CODE, triggerSb.toString());
+		} else if (executorRouteStrategyEnum == ExecutorRouteStrategyEnum.BUSYOVER) {
+			for (String address : addressList) {
+				// beat
+				ReturnT<String> idleBeatResult = null;
+				try {
+					ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, address).getObject();
+					idleBeatResult = executorBiz.idleBeat(triggerParam.getJobId());
+				} catch (Exception e) {
+					logger.error("", e);
+					idleBeatResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
+				}
+				triggerSb.append("<br>----------------------<br>")
+						.append("空闲检测:")
+						.append("<br>address:").append(address)
+						.append("<br>code:").append(idleBeatResult.getCode())
+						.append("<br>msg:").append(idleBeatResult.getMsg());
 
-					if (beatResult.getCode() == ReturnT.SUCCESS_CODE) {
-						jobLog.setExecutorAddress(address);
+				// beat success
+				if (idleBeatResult.getCode() == ReturnT.SUCCESS_CODE) {
+					jobLog.setExecutorAddress(address);
 
-						ReturnT<String> runResult = runExecutor(triggerParam, address);
-						triggerSb.append("<br>----------------------<br>").append(runResult.getMsg());
+					ReturnT<String> runResult = runExecutor(triggerParam, address);
+					triggerSb.append("<br>----------------------<br>").append(runResult.getMsg());
 
-						return new ReturnT<String>(runResult.getCode(), triggerSb.toString());
-					}
+					return new ReturnT<String>(runResult.getCode(), triggerSb.toString());
 				}
-				return new ReturnT<String>(ReturnT.FAIL_CODE, triggerSb.toString());
 			}
-		}
-	}
-
-	/**
-	 * run executor
-	 * @param address
-	 * @return
-	 */
-	public ReturnT<String> beatExecutor(String address){
-		ReturnT<String> beatResult = null;
-		try {
-			ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, address).getObject();
-			beatResult = executorBiz.beat();
-		} catch (Exception e) {
-			logger.error("", e);
-			beatResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
-		}
+			return new ReturnT<String>(ReturnT.FAIL_CODE, triggerSb.toString());
+		} else {
+			// get address
+			String address = executorRouteStrategyEnum.getRouter().route(jobInfo.getId(), addressList);
+			jobLog.setExecutorAddress(address);
 
-		StringBuffer sb = new StringBuffer("心跳检测:");
-		sb.append("<br>address:").append(address);
-		sb.append("<br>code:").append(beatResult.getCode());
-		sb.append("<br>msg:").append(beatResult.getMsg());
-		beatResult.setMsg(sb.toString());
+			// run
+			ReturnT<String> runResult = runExecutor(triggerParam, address);
+			triggerSb.append("<br>----------------------<br>").append(runResult.getMsg());
 
-		return beatResult;
+			return new ReturnT<String>(runResult.getCode(), triggerSb.toString());
+		}
 	}
 
 	/**

+ 2 - 1
xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java

@@ -14,7 +14,8 @@ public enum ExecutorRouteStrategyEnum {
     CONSISTENT_HASH("一致性HASH", new ExecutorRouteConsistentHash()),
     LEAST_FREQUENTLY_USED("最不经常使用", new ExecutorRouteLFU()),
     LEAST_RECENTLY_USED("最近最久未使用", new ExecutorRouteLRU()),
-    FAILOVER("故障转移", null);
+    FAILOVER("故障转移", null),
+    BUSYOVER("忙碌转移", null);
 
     ExecutorRouteStrategyEnum(String title, ExecutorRouter router) {
         this.title = title;

+ 8 - 0
xxl-job-core/src/main/java/com/xxl/job/core/biz/ExecutorBiz.java

@@ -15,6 +15,14 @@ public interface ExecutorBiz {
      */
     public ReturnT<String> beat();
 
+    /**
+     * idle beat
+     *
+     * @param jobId
+     * @return
+     */
+    public ReturnT<String> idleBeat(int jobId);
+
     /**
      * kill
      * @param jobId

+ 16 - 0
xxl-job-core/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java

@@ -29,6 +29,22 @@ public class ExecutorBizImpl implements ExecutorBiz {
         return ReturnT.SUCCESS;
     }
 
+    @Override
+    public ReturnT<String> idleBeat(int jobId) {
+
+        // isRunningOrHasQueue
+        boolean isRunningOrHasQueue = false;
+        JobThread jobThread = XxlJobExecutor.loadJobThread(jobId);
+        if (jobThread != null && jobThread.isRunningOrHasQueue()) {
+            isRunningOrHasQueue = true;
+        }
+
+        if (isRunningOrHasQueue) {
+            return new ReturnT<String>(ReturnT.FAIL_CODE, "job thread is running or has trigger queue.");
+        }
+        return ReturnT.SUCCESS;
+    }
+
     @Override
     public ReturnT<String> kill(int jobId) {
         // kill handlerThread, and create new one

+ 2 - 1
xxl-job-core/src/main/java/com/xxl/job/core/thread/ExecutorRegistryThread.java

@@ -46,7 +46,8 @@ public class ExecutorRegistryThread extends Thread {
                     try {
                         RegistryParam registryParam = new RegistryParam(RegistryConfig.RegistType.EXECUTOR.name(), appName, executorAddress);
                         ReturnT<String> registryResult = AdminApiUtil.callApiFailover(AdminApiUtil.REGISTRY, registryParam);
-                        logger.info(">>>>>>>>>>> xxl-job registry, RegistryParam:{}, registryResult:{}", new Object[]{registryParam.toString(), registryResult.toString()});
+                        logger.info(">>>>>>>>>>> xxl-job Executor registry {}, RegistryParam:{}, registryResult:{}",
+                                new Object[]{(registryResult.getCode()==ReturnT.SUCCESS_CODE?"success":"fail"), registryParam.toString(), registryResult.toString()});
                     } catch (Exception e) {
                         logger.error(">>>>>>>>>>> xxl-job ExecutorRegistryThread Exception:", e);
                     }