执行器AccessToken:执行器维度隔离设置,提升安全性;线上化动态管理,提升操作效率及体验;

(注意:因为AccessToken调整为执行器维度,OpenAPI通讯协议部分发生变化,调度中心与执行器需要一并升级至v3.5.0;)
master
xuxueli 3 months ago
parent bbb031f57e
commit 954e467e84

@ -2903,13 +2903,14 @@ alter table xxl_job_log
### 7.47 版本 v3.5.0 Release Notes[ING] ### 7.47 版本 v3.5.0 Release Notes[ING]
- 1、【新增】GLUE模式开关新增GLUE模式开关xxl.job.executor.glueenabled支持执行器维度设置是否启用GLUE模式 - 1、【新增】GLUE模式开关新增GLUE模式开关xxl.job.executor.glueenabled支持执行器维度设置是否启用GLUE模式
- 2、【TODO】执行器AccessToken执行器维度AccessToken线上化动态管理执行器间AccessToken隔离提升安全性 - 2、【新增】执行器AccessToken执行器维度隔离设置提升安全性线上化动态管理提升操作效率及体验
- 执行器ExecutorBiz 服务处理、AdminBiz请求发起统一附加 appname + accessToken 注意因为AccessToken调整为执行器维度OpenAPI通讯协议部分发生变化调度中心与执行器需要一并升级至v3.5.0
- 调度中心AppName 限制不可重复 + accessToken 必填JobGoup本地缓存AdminBiz 服务处理 校验参数; - 3、【调整】执行器约束规则调整AppName限制不可重复
- 3、【TODO】调度中心OpenAPI增强提供任务管理能力封装Agent Skill并推送ClawHub - 4、【TODO】调度中心OpenAPI增强提供任务管理能力封装Agent Skill并推送ClawHub
- 4、【TODO】配置线上化发送邮箱配置线上管理、线程池配置调整 - 5、【TODO】配置线上化发送邮箱配置线上管理、线程池配置调整
- 5、【TODO】任务告警拆分“告警类型、告警配置”属性支持Webhook、邮箱多种方式 - 6、【TODO】任务告警拆分“告警类型、告警配置”属性支持Webhook、邮箱多种方式
- 6、【TODO】任务说明拆分“任务名称、任务备注”属性前者用于任务检索后者用于补充任务描述。 - 7、【TODO】任务说明拆分“任务名称、任务备注”属性前者用于任务检索后者用于补充任务描述。
### TODO LIST ### TODO LIST
- 1、调度隔离调度中心针对不同执行器各自维护不同的调度和远程触发组件。 - 1、调度隔离调度中心针对不同执行器各自维护不同的调度和远程触发组件。

@ -11,12 +11,13 @@ SET NAMES utf8mb4;
CREATE TABLE `xxl_job_group` CREATE TABLE `xxl_job_group`
( (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`app_name` varchar(64) NOT NULL COMMENT '执行器AppName', `app_name` varchar(64) NOT NULL COMMENT '执行器AppName',
`title` varchar(64) NOT NULL COMMENT '执行器名称', `title` varchar(64) NOT NULL COMMENT '执行器名称',
`address_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行器地址类型0=自动注册、1=手动录入', `address_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行器地址类型0=自动注册、1=手动录入',
`address_list` text COMMENT '执行器地址列表,多地址逗号分隔', `address_list` text DEFAULT NULL COMMENT '执行器地址列表,多地址逗号分隔',
`update_time` datetime DEFAULT NULL, `access_token` varchar(255) DEFAULT NULL COMMENT '执行器AccessToken',
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `i_app_name` (`app_name`) USING BTREE UNIQUE KEY `i_app_name` (`app_name`) USING BTREE
) ENGINE = InnoDB ) ENGINE = InnoDB
@ -146,9 +147,9 @@ CREATE TABLE `xxl_job_user`
## —————————————————————— for default data —————————————————— ## —————————————————————— for default data ——————————————————
INSERT INTO `xxl_job_group`(`id`, `app_name`, `title`, `address_type`, `address_list`, `update_time`) INSERT INTO `xxl_job_group`(`id`, `app_name`, `title`, `address_type`, `address_list`, `access_token`, `update_time`)
VALUES (1, 'xxl-job-executor-sample', '通用执行器Sample', 0, NULL, now()), VALUES (1, 'xxl-job-executor-sample', '通用执行器Sample', 0, NULL, 'default_token', now()),
(2, 'xxl-job-executor-sample-ai', 'AI执行器Sample', 0, NULL, now()); (2, 'xxl-job-executor-sample-ai', 'AI执行器Sample', 0, NULL, 'default_token', now());
INSERT INTO `xxl_job_info`(`id`, `job_group`, `job_desc`, `add_time`, `update_time`, `author`, `alarm_email`, INSERT INTO `xxl_job_info`(`id`, `job_group`, `job_desc`, `add_time`, `update_time`, `author`, `alarm_email`,
`schedule_type`, `schedule_conf`, `misfire_strategy`, `executor_route_strategy`, `schedule_type`, `schedule_conf`, `misfire_strategy`, `executor_route_strategy`,

@ -78,7 +78,7 @@ public class JobCodeController {
return Response.ofFail( (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_glue_remark")) ); return Response.ofFail( (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_glue_remark")) );
} }
if (glueRemark.length()<4 || glueRemark.length()>100) { if (glueRemark.length()<4 || glueRemark.length()>100) {
return Response.ofFail(I18nUtil.getString("jobinfo_glue_remark_limit")); return Response.ofFail(I18nUtil.getString("jobinfo_glue_remark") + I18nUtil.getString("system_length_limit") + " 4~100");
} }
if (XssUtil.hasXss(glueRemark)) { if (XssUtil.hasXss(glueRemark)) {
return Response.ofFail(I18nUtil.getString("jobinfo_glue_remark") + I18nUtil.getString("system_invalid")); return Response.ofFail(I18nUtil.getString("jobinfo_glue_remark") + I18nUtil.getString("system_invalid"));

@ -77,7 +77,7 @@ public class JobGroupController {
return Response.ofFail((I18nUtil.getString("system_please_input")+"AppName") ); return Response.ofFail((I18nUtil.getString("system_please_input")+"AppName") );
} }
if (xxlJobGroup.getAppname().length()<4 || xxlJobGroup.getAppname().length()>64) { if (xxlJobGroup.getAppname().length()<4 || xxlJobGroup.getAppname().length()>64) {
return Response.ofFail( I18nUtil.getString("jobgroup_field_appname_length") ); return Response.ofFail( "AppName " + I18nUtil.getString("system_length_limit") + "4~64");
} }
if (XssUtil.hasXss(xxlJobGroup.getAppname())) { if (XssUtil.hasXss(xxlJobGroup.getAppname())) {
return Response.ofFail( "AppName"+I18nUtil.getString("system_invalid") ); return Response.ofFail( "AppName"+I18nUtil.getString("system_invalid") );

@ -193,10 +193,13 @@ public class JobLogController {
// valid JobGroup permission // valid JobGroup permission
JobGroupPermissionUtil.validJobGroupPermission(request, jobInfo.getJobGroup()); JobGroupPermissionUtil.validJobGroupPermission(request, jobInfo.getJobGroup());
// load group
XxlJobGroup jobGroup = XxlJobAdminBootstrap.getInstance().getXxlJobGroupMapper().load(log.getJobGroup());
// request of kill // request of kill
Response<String> runResult = null; Response<String> runResult = null;
try { try {
ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(log.getExecutorAddress()); ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(log.getExecutorAddress(), jobGroup);
runResult = executorBiz.kill(new KillRequest(jobInfo.getId())); runResult = executorBiz.kill(new KillRequest(jobInfo.getId()));
} catch (Exception e) { } catch (Exception e) {
logger.error(e.getMessage(), e); logger.error(e.getMessage(), e);
@ -297,8 +300,11 @@ public class JobLogController {
// valid permission // valid permission
JobGroupPermissionUtil.validJobGroupPermission(request, jobLog.getJobGroup()); JobGroupPermissionUtil.validJobGroupPermission(request, jobLog.getJobGroup());
// load group
XxlJobGroup jobGroup = XxlJobAdminBootstrap.getInstance().getXxlJobGroupMapper().load(jobLog.getJobGroup());
// log cat // log cat
ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(jobLog.getExecutorAddress()); ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(jobLog.getExecutorAddress(), jobGroup);
Response<LogData> logResult = executorBiz.log(new LogRequest(logId, jobLog.getTriggerTime().getTime(), fromLineNum)); Response<LogData> logResult = executorBiz.log(new LogRequest(logId, jobLog.getTriggerTime().getTime(), fromLineNum));
// is end // is end

@ -1,6 +1,7 @@
package com.xxl.job.admin.business.scheduler.config; package com.xxl.job.admin.business.scheduler.config;
import com.xxl.job.admin.business.mapper.*; import com.xxl.job.admin.business.mapper.*;
import com.xxl.job.admin.business.model.XxlJobGroup;
import com.xxl.job.admin.business.scheduler.alarm.JobAlarmer; import com.xxl.job.admin.business.scheduler.alarm.JobAlarmer;
import com.xxl.job.admin.business.scheduler.complete.JobCompleter; import com.xxl.job.admin.business.scheduler.complete.JobCompleter;
import com.xxl.job.admin.business.scheduler.thread.*; import com.xxl.job.admin.business.scheduler.thread.*;
@ -135,27 +136,41 @@ public class XxlJobAdminBootstrap implements InitializingBean, DisposableBean {
// ---------------------- executor-client ---------------------- // ---------------------- executor-client ----------------------
private static ConcurrentMap<String, ExecutorBiz> executorBizRepository = new ConcurrentHashMap<>(); private static final ConcurrentMap<String, ExecutorBiz> executorBizRepository = new ConcurrentHashMap<>();
public static ExecutorBiz getExecutorBiz(String address) throws Exception { private static final int EXECUTOR_BIZ_CACHE_MAX_SIZE = 1000;
/**
* get executor-client
*/
public static ExecutorBiz getExecutorBiz(String address, XxlJobGroup xxlJobGroup) throws Exception {
// valid // valid
if (StringTool.isBlank(address)) { if (StringTool.isBlank(address) || xxlJobGroup == null) {
return null; return null;
} }
address = address.trim();
String accessToken = xxlJobGroup.getAccessToken();
String appname = xxlJobGroup.getAppname();
// load-cache // load-cache
address = address.trim(); String cacheKey = address + "|" + accessToken + "|" + appname;
ExecutorBiz executorBiz = executorBizRepository.get(address); ExecutorBiz executorBiz = executorBizRepository.get(cacheKey);
if (executorBiz != null) { if (executorBiz != null) {
return executorBiz; return executorBiz;
} }
// set-cache // new client
executorBiz = HttpTool.createClient() executorBiz = HttpTool.createClient()
.url(address) .url(address)
.timeout(XxlJobAdminBootstrap.getInstance().getTimeout() * 1000) .timeout(XxlJobAdminBootstrap.getInstance().getTimeout() * 1000)
.header(Const.XXL_JOB_ACCESS_TOKEN, XxlJobAdminBootstrap.getInstance().getAccessToken()) .header(Const.XXL_JOB_ACCESS_TOKEN, accessToken)
.header(Const.XXL_JOB_APPNAME, appname)
.proxy(ExecutorBiz.class); .proxy(ExecutorBiz.class);
executorBizRepository.put(address, executorBiz); executorBizRepository.put(cacheKey, executorBiz);
// avoid unbounded growth
if (executorBizRepository.size() > EXECUTOR_BIZ_CACHE_MAX_SIZE) {
executorBizRepository.clear();
}
return executorBiz; return executorBiz;
} }
@ -166,9 +181,6 @@ public class XxlJobAdminBootstrap implements InitializingBean, DisposableBean {
@Value("${xxl.job.i18n}") @Value("${xxl.job.i18n}")
private String i18n; private String i18n;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${xxl.job.timeout}") @Value("${xxl.job.timeout}")
private int timeout; private int timeout;
@ -221,10 +233,6 @@ public class XxlJobAdminBootstrap implements InitializingBean, DisposableBean {
return i18n; return i18n;
} }
public String getAccessToken() {
return accessToken;
}
public int getTimeout() { public int getTimeout() {
return timeout; return timeout;
} }

@ -1,12 +1,11 @@
package com.xxl.job.admin.business.scheduler.route; package com.xxl.job.admin.business.scheduler.route;
import com.xxl.job.admin.business.model.XxlJobGroup;
import com.xxl.job.core.openapi.executor.dto.TriggerRequest; import com.xxl.job.core.openapi.executor.dto.TriggerRequest;
import com.xxl.tool.response.Response; import com.xxl.tool.response.Response;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.List;
/** /**
* Created by xuxueli on 17/3/10. * Created by xuxueli on 17/3/10.
*/ */
@ -16,9 +15,10 @@ public abstract class ExecutorRouter {
/** /**
* route address * route address
* *
* @param addressList executor address list * @param triggerRequest trigger request
* @param jobGroup executor group
* @return ReturnT.content=address * @return ReturnT.content=address
*/ */
public abstract Response<String> route(TriggerRequest triggerParam, List<String> addressList); public abstract Response<String> route(TriggerRequest triggerRequest, XxlJobGroup jobGroup);
} }

@ -1,5 +1,6 @@
package com.xxl.job.admin.business.scheduler.route.strategy; package com.xxl.job.admin.business.scheduler.route.strategy;
import com.xxl.job.admin.business.model.XxlJobGroup;
import com.xxl.job.admin.business.scheduler.config.XxlJobAdminBootstrap; import com.xxl.job.admin.business.scheduler.config.XxlJobAdminBootstrap;
import com.xxl.job.admin.business.scheduler.route.ExecutorRouter; import com.xxl.job.admin.business.scheduler.route.ExecutorRouter;
import com.xxl.job.admin.framework.util.I18nUtil; import com.xxl.job.admin.framework.util.I18nUtil;
@ -16,13 +17,15 @@ import java.util.List;
public class ExecutorRouteBusyover extends ExecutorRouter { public class ExecutorRouteBusyover extends ExecutorRouter {
@Override @Override
public Response<String> route(TriggerRequest triggerParam, List<String> addressList) { public Response<String> route(TriggerRequest triggerParam, XxlJobGroup jobGroup) {
List<String> addressList = jobGroup.getRegistryList();
StringBuffer idleBeatResultSB = new StringBuffer(); StringBuffer idleBeatResultSB = new StringBuffer();
for (String address : addressList) { for (String address : addressList) {
// beat // beat
Response<String> idleBeatResult = null; Response<String> idleBeatResult = null;
try { try {
ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(address); ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(address, jobGroup);
idleBeatResult = executorBiz.idleBeat(new IdleBeatRequest(triggerParam.getJobId())); idleBeatResult = executorBiz.idleBeat(new IdleBeatRequest(triggerParam.getJobId()));
} catch (Exception e) { } catch (Exception e) {
logger.error(e.getMessage(), e); logger.error(e.getMessage(), e);

@ -1,5 +1,6 @@
package com.xxl.job.admin.business.scheduler.route.strategy; package com.xxl.job.admin.business.scheduler.route.strategy;
import com.xxl.job.admin.business.model.XxlJobGroup;
import com.xxl.job.admin.business.scheduler.route.ExecutorRouter; import com.xxl.job.admin.business.scheduler.route.ExecutorRouter;
import com.xxl.job.core.openapi.executor.dto.TriggerRequest; import com.xxl.job.core.openapi.executor.dto.TriggerRequest;
import com.xxl.tool.response.Response; import com.xxl.tool.response.Response;
@ -91,7 +92,8 @@ public class ExecutorRouteConsistentHash extends ExecutorRouter {
} }
@Override @Override
public Response<String> route(TriggerRequest triggerParam, List<String> addressList) { public Response<String> route(TriggerRequest triggerParam, XxlJobGroup jobGroup) {
List<String> addressList = jobGroup.getRegistryList();
String address = hashJob(triggerParam.getJobId(), addressList); String address = hashJob(triggerParam.getJobId(), addressList);
return Response.ofSuccess(address); return Response.ofSuccess(address);
} }

@ -1,5 +1,6 @@
package com.xxl.job.admin.business.scheduler.route.strategy; package com.xxl.job.admin.business.scheduler.route.strategy;
import com.xxl.job.admin.business.model.XxlJobGroup;
import com.xxl.job.admin.business.scheduler.config.XxlJobAdminBootstrap; import com.xxl.job.admin.business.scheduler.config.XxlJobAdminBootstrap;
import com.xxl.job.admin.business.scheduler.route.ExecutorRouter; import com.xxl.job.admin.business.scheduler.route.ExecutorRouter;
import com.xxl.job.admin.framework.util.I18nUtil; import com.xxl.job.admin.framework.util.I18nUtil;
@ -15,14 +16,16 @@ import java.util.List;
public class ExecutorRouteFailover extends ExecutorRouter { public class ExecutorRouteFailover extends ExecutorRouter {
@Override @Override
public Response<String> route(TriggerRequest triggerParam, List<String> addressList) { public Response<String> route(TriggerRequest triggerParam, XxlJobGroup jobGroup) {
List<String> addressList = jobGroup.getRegistryList();
StringBuffer beatResultSB = new StringBuffer(); StringBuffer beatResultSB = new StringBuffer();
for (String address : addressList) { for (String address : addressList) {
// beat // beat
Response<String> beatResult = null; Response<String> beatResult = null;
try { try {
ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(address); ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(address, jobGroup);
beatResult = executorBiz.beat(); beatResult = executorBiz.beat();
} catch (Exception e) { } catch (Exception e) {
logger.error(e.getMessage(), e); logger.error(e.getMessage(), e);

@ -1,19 +1,18 @@
package com.xxl.job.admin.business.scheduler.route.strategy; package com.xxl.job.admin.business.scheduler.route.strategy;
import com.xxl.job.admin.business.model.XxlJobGroup;
import com.xxl.job.admin.business.scheduler.route.ExecutorRouter; import com.xxl.job.admin.business.scheduler.route.ExecutorRouter;
import com.xxl.job.core.openapi.executor.dto.TriggerRequest; import com.xxl.job.core.openapi.executor.dto.TriggerRequest;
import com.xxl.tool.response.Response; import com.xxl.tool.response.Response;
import java.util.List;
/** /**
* Created by xuxueli on 17/3/10. * Created by xuxueli on 17/3/10.
*/ */
public class ExecutorRouteFirst extends ExecutorRouter { public class ExecutorRouteFirst extends ExecutorRouter {
@Override @Override
public Response<String> route(TriggerRequest triggerParam, List<String> addressList){ public Response<String> route(TriggerRequest triggerParam, XxlJobGroup jobGroup){
return Response.ofSuccess(addressList.get(0)); return Response.ofSuccess(jobGroup.getRegistryList().get(0));
} }
} }

@ -1,5 +1,6 @@
package com.xxl.job.admin.business.scheduler.route.strategy; package com.xxl.job.admin.business.scheduler.route.strategy;
import com.xxl.job.admin.business.model.XxlJobGroup;
import com.xxl.job.admin.business.scheduler.route.ExecutorRouter; import com.xxl.job.admin.business.scheduler.route.ExecutorRouter;
import com.xxl.job.core.openapi.executor.dto.TriggerRequest; import com.xxl.job.core.openapi.executor.dto.TriggerRequest;
import com.xxl.tool.response.Response; import com.xxl.tool.response.Response;
@ -70,7 +71,8 @@ public class ExecutorRouteLFU extends ExecutorRouter {
} }
@Override @Override
public Response<String> route(TriggerRequest triggerParam, List<String> addressList) { public Response<String> route(TriggerRequest triggerParam, XxlJobGroup jobGroup) {
List<String> addressList = jobGroup.getRegistryList();
String address = route(triggerParam.getJobId(), addressList); String address = route(triggerParam.getJobId(), addressList);
return Response.ofSuccess(address); return Response.ofSuccess(address);
} }

@ -1,5 +1,6 @@
package com.xxl.job.admin.business.scheduler.route.strategy; package com.xxl.job.admin.business.scheduler.route.strategy;
import com.xxl.job.admin.business.model.XxlJobGroup;
import com.xxl.job.admin.business.scheduler.route.ExecutorRouter; import com.xxl.job.admin.business.scheduler.route.ExecutorRouter;
import com.xxl.job.core.openapi.executor.dto.TriggerRequest; import com.xxl.job.core.openapi.executor.dto.TriggerRequest;
import com.xxl.tool.response.Response; import com.xxl.tool.response.Response;
@ -72,7 +73,8 @@ public class ExecutorRouteLRU extends ExecutorRouter {
} }
@Override @Override
public Response<String> route(TriggerRequest triggerParam, List<String> addressList) { public Response<String> route(TriggerRequest triggerParam, XxlJobGroup jobGroup) {
List<String> addressList = jobGroup.getRegistryList();
String address = route(triggerParam.getJobId(), addressList); String address = route(triggerParam.getJobId(), addressList);
return Response.ofSuccess(address); return Response.ofSuccess(address);
} }

@ -1,19 +1,18 @@
package com.xxl.job.admin.business.scheduler.route.strategy; package com.xxl.job.admin.business.scheduler.route.strategy;
import com.xxl.job.admin.business.model.XxlJobGroup;
import com.xxl.job.admin.business.scheduler.route.ExecutorRouter; import com.xxl.job.admin.business.scheduler.route.ExecutorRouter;
import com.xxl.job.core.openapi.executor.dto.TriggerRequest; import com.xxl.job.core.openapi.executor.dto.TriggerRequest;
import com.xxl.tool.response.Response; import com.xxl.tool.response.Response;
import java.util.List;
/** /**
* Created by xuxueli on 17/3/10. * Created by xuxueli on 17/3/10.
*/ */
public class ExecutorRouteLast extends ExecutorRouter { public class ExecutorRouteLast extends ExecutorRouter {
@Override @Override
public Response<String> route(TriggerRequest triggerParam, List<String> addressList) { public Response<String> route(TriggerRequest triggerParam, XxlJobGroup jobGroup) {
return Response.ofSuccess(addressList.get(addressList.size()-1)); return Response.ofSuccess(jobGroup.getRegistryList().get(jobGroup.getRegistryList().size()-1));
} }
} }

@ -1,5 +1,6 @@
package com.xxl.job.admin.business.scheduler.route.strategy; package com.xxl.job.admin.business.scheduler.route.strategy;
import com.xxl.job.admin.business.model.XxlJobGroup;
import com.xxl.job.admin.business.scheduler.route.ExecutorRouter; import com.xxl.job.admin.business.scheduler.route.ExecutorRouter;
import com.xxl.job.core.openapi.executor.dto.TriggerRequest; import com.xxl.job.core.openapi.executor.dto.TriggerRequest;
import com.xxl.tool.response.Response; import com.xxl.tool.response.Response;
@ -15,7 +16,8 @@ public class ExecutorRouteRandom extends ExecutorRouter {
private static Random localRandom = new Random(); private static Random localRandom = new Random();
@Override @Override
public Response<String> route(TriggerRequest triggerParam, List<String> addressList) { public Response<String> route(TriggerRequest triggerParam, XxlJobGroup jobGroup) {
List<String> addressList = jobGroup.getRegistryList();
String address = addressList.get(localRandom.nextInt(addressList.size())); String address = addressList.get(localRandom.nextInt(addressList.size()));
return Response.ofSuccess(address); return Response.ofSuccess(address);
} }

@ -1,5 +1,6 @@
package com.xxl.job.admin.business.scheduler.route.strategy; package com.xxl.job.admin.business.scheduler.route.strategy;
import com.xxl.job.admin.business.model.XxlJobGroup;
import com.xxl.job.admin.business.scheduler.route.ExecutorRouter; import com.xxl.job.admin.business.scheduler.route.ExecutorRouter;
import com.xxl.job.core.openapi.executor.dto.TriggerRequest; import com.xxl.job.core.openapi.executor.dto.TriggerRequest;
import com.xxl.tool.response.Response; import com.xxl.tool.response.Response;
@ -38,7 +39,8 @@ public class ExecutorRouteRound extends ExecutorRouter {
} }
@Override @Override
public Response<String> route(TriggerRequest triggerParam, List<String> addressList) { public Response<String> route(TriggerRequest triggerParam, XxlJobGroup jobGroup) {
List<String> addressList = jobGroup.getRegistryList();
String address = addressList.get(count(triggerParam.getJobId())%addressList.size()); String address = addressList.get(count(triggerParam.getJobId())%addressList.size());
return Response.ofSuccess(address); return Response.ofSuccess(address);
} }

@ -178,7 +178,7 @@ public class JobTrigger {
address = group.getRegistryList().get(0); address = group.getRegistryList().get(0);
} }
} else { } else {
routeAddressResult = executorRouteStrategyEnum.getRouter().route(triggerParam, group.getRegistryList()); routeAddressResult = executorRouteStrategyEnum.getRouter().route(triggerParam, group);
if (routeAddressResult.isSuccess()) { if (routeAddressResult.isSuccess()) {
address = routeAddressResult.getData(); address = routeAddressResult.getData();
} }
@ -190,7 +190,7 @@ public class JobTrigger {
// 4、trigger remote executor // 4、trigger remote executor
Response<String> triggerResult = null; Response<String> triggerResult = null;
if (address != null) { if (address != null) {
triggerResult = doTrigger(triggerParam, address); triggerResult = doTrigger(triggerParam, address, group);
} else { } else {
triggerResult = Response.of(XxlJobContext.HANDLE_CODE_FAIL, "Address Router Fail."); triggerResult = Response.of(XxlJobContext.HANDLE_CODE_FAIL, "Address Router Fail.");
} }
@ -253,12 +253,13 @@ public class JobTrigger {
* *
* @param triggerParam trigger param * @param triggerParam trigger param
* @param address the address * @param address the address
* @param jobGroup job group
* @return return * @return return
*/ */
private Response<String> doTrigger(TriggerRequest triggerParam, String address){ private Response<String> doTrigger(TriggerRequest triggerParam, String address, XxlJobGroup jobGroup){
try { try {
// build client // build client
ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(address); ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(address, jobGroup);
// invoke // invoke
Response<String> runResult = executorBiz.trigger(triggerParam); Response<String> runResult = executorBiz.trigger(triggerParam);

@ -55,9 +55,6 @@ spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
### xxl-job, access token
xxl.job.accessToken=default_token
### xxl-job, request executor timeout, by second, default 3s ### xxl-job, request executor timeout, by second, default 3s
xxl.job.timeout=3 xxl.job.timeout=3

@ -138,7 +138,6 @@ jobinfo_opt_registryinfo=Registry Info
jobinfo_opt_next_time=Next trigger time jobinfo_opt_next_time=Next trigger time
jobinfo_glue_source=GLUE Source jobinfo_glue_source=GLUE Source
jobinfo_glue_remark=Resource Remark jobinfo_glue_remark=Resource Remark
jobinfo_glue_remark_limit=Resource Remark length is limited to 4~100
jobinfo_glue_rollback=Version Backtrack jobinfo_glue_rollback=Version Backtrack
jobinfo_glue_jobid_invalid=Job ID is illegal jobinfo_glue_jobid_invalid=Job ID is illegal
jobinfo_glue_gluetype_invalid=The job is not GLUE Type jobinfo_glue_gluetype_invalid=The job is not GLUE Type
@ -212,8 +211,7 @@ jobgroup_field_registryList=machine address
jobgroup_field_registryList_invalid=registry machine address is illegal jobgroup_field_registryList_invalid=registry machine address is illegal
jobgroup_field_registryList_placeholder=Please enter the machine address, if there are more than one comma separated jobgroup_field_registryList_placeholder=Please enter the machine address, if there are more than one comma separated
jobgroup_field_appname_limit=Limit the beginning of a lowercase letter, consists of lowercase letters、number and hyphen. jobgroup_field_appname_limit=Limit the beginning of a lowercase letter, consists of lowercase letters、number and hyphen.
jobgroup_field_appname_length=AppName length is limited to 4~64 jobgroup_field_accesstoken_limit=Limit the beginning of a lowercase letter, consists of lowercase letters and number.
jobgroup_field_title_length=Title length is limited to 4~12
jobgroup_field_order_digits=Please enter a positive integer jobgroup_field_order_digits=Please enter a positive integer
jobgroup_field_orderrange=Order is limited to 1~1000 jobgroup_field_orderrange=Order is limited to 1~1000
jobgroup_del_limit_0=Refuse to delete, the executor is being used jobgroup_del_limit_0=Refuse to delete, the executor is being used

@ -31,7 +31,7 @@ system_invalid=非法
system_not_found=不存在 system_not_found=不存在
system_nav=导航 system_nav=导航
system_digits=整数 system_digits=整数
system_length_limit=长度限制 system_length_limit=长度限制
system_permission_limit=权限拦截 system_permission_limit=权限拦截
system_welcome=欢迎 system_welcome=欢迎
system_num_range=数值范围限制 system_num_range=数值范围限制
@ -138,7 +138,6 @@ jobinfo_opt_registryinfo=注册节点
jobinfo_opt_next_time=下次执行时间 jobinfo_opt_next_time=下次执行时间
jobinfo_glue_source=GLUE源码 jobinfo_glue_source=GLUE源码
jobinfo_glue_remark=源码备注 jobinfo_glue_remark=源码备注
jobinfo_glue_remark_limit=源码备注长度限制为4~100
jobinfo_glue_rollback=版本回溯 jobinfo_glue_rollback=版本回溯
jobinfo_glue_jobid_invalid=任务ID非法 jobinfo_glue_jobid_invalid=任务ID非法
jobinfo_glue_gluetype_invalid=该任务非GLUE模式 jobinfo_glue_gluetype_invalid=该任务非GLUE模式
@ -212,8 +211,7 @@ jobgroup_field_registryList=机器地址
jobgroup_field_registryList_invalid=机器地址格式非法 jobgroup_field_registryList_invalid=机器地址格式非法
jobgroup_field_registryList_placeholder=请输入执行器地址列表,多地址逗号分隔 jobgroup_field_registryList_placeholder=请输入执行器地址列表,多地址逗号分隔
jobgroup_field_appname_limit=限制以小写字母开头,由小写字母、数字和中划线组成 jobgroup_field_appname_limit=限制以小写字母开头,由小写字母、数字和中划线组成
jobgroup_field_appname_length=AppName长度限制为4~64 jobgroup_field_accesstoken_limit=限制以小写字母开头,由小写字母、数字组成
jobgroup_field_title_length=名称长度限制为4~12
jobgroup_field_order_digits=请输入整数 jobgroup_field_order_digits=请输入整数
jobgroup_field_orderrange=取值范围为1~1000 jobgroup_field_orderrange=取值范围为1~1000
jobgroup_del_limit_0=拒绝删除,该执行器使用中 jobgroup_del_limit_0=拒绝删除,该执行器使用中

@ -31,7 +31,7 @@ system_invalid=非法
system_not_found=不存在 system_not_found=不存在
system_nav=導航 system_nav=導航
system_digits=整數 system_digits=整數
system_length_limit=長度限制 system_length_limit=長度限制
system_permission_limit=權限控管 system_permission_limit=權限控管
system_welcome=歡迎 system_welcome=歡迎
system_num_range=數值範圍限制 system_num_range=數值範圍限制
@ -138,7 +138,6 @@ jobinfo_opt_registryinfo=注冊節點
jobinfo_opt_next_time=下次執行時間 jobinfo_opt_next_time=下次執行時間
jobinfo_glue_source=GLUE源碼 jobinfo_glue_source=GLUE源碼
jobinfo_glue_remark=源碼備註 jobinfo_glue_remark=源碼備註
jobinfo_glue_remark_limit=源碼備註長度限制為4~100
jobinfo_glue_rollback=版本回復 jobinfo_glue_rollback=版本回復
jobinfo_glue_jobid_invalid=任務ID非法 jobinfo_glue_jobid_invalid=任務ID非法
jobinfo_glue_gluetype_invalid=該任務非GLUE模式 jobinfo_glue_gluetype_invalid=該任務非GLUE模式
@ -212,8 +211,7 @@ jobgroup_field_registryList=機器地址
jobgroup_field_registryList_invalid=機器地址格式非法 jobgroup_field_registryList_invalid=機器地址格式非法
jobgroup_field_registryList_placeholder=請輸入執行器地址列表,多個地址請以逗號分隔 jobgroup_field_registryList_placeholder=請輸入執行器地址列表,多個地址請以逗號分隔
jobgroup_field_appname_limit=限制以小寫字母開頭,由小寫字母、數字和中划線組成 jobgroup_field_appname_limit=限制以小寫字母開頭,由小寫字母、數字和中划線組成
jobgroup_field_appname_length=AppName長度限制為4~64 jobgroup_field_accesstoken_limit=限制以小寫字母開頭,由小寫字母、數字組成
jobgroup_field_title_length=名稱長度限制為4~12
jobgroup_field_order_digits=請輸入整數 jobgroup_field_order_digits=請輸入整數
jobgroup_field_orderrange=取值範圍為1~1000 jobgroup_field_orderrange=取值範圍為1~1000
jobgroup_del_limit_0=拒絕刪除,該執行器使用中 jobgroup_del_limit_0=拒絕刪除,該執行器使用中

@ -9,6 +9,7 @@
<result column="title" property="title" /> <result column="title" property="title" />
<result column="address_type" property="addressType" /> <result column="address_type" property="addressType" />
<result column="address_list" property="addressList" /> <result column="address_list" property="addressList" />
<result column="access_token" property="accessToken" />
<result column="update_time" property="updateTime" /> <result column="update_time" property="updateTime" />
</resultMap> </resultMap>
@ -18,6 +19,7 @@
t.title, t.title,
t.address_type, t.address_type,
t.address_list, t.address_list,
t.access_token,
t.update_time t.update_time
</sql> </sql>
@ -35,8 +37,8 @@
</select> </select>
<insert id="save" parameterType="com.xxl.job.admin.business.model.XxlJobGroup" useGeneratedKeys="true" keyProperty="id" > <insert id="save" parameterType="com.xxl.job.admin.business.model.XxlJobGroup" useGeneratedKeys="true" keyProperty="id" >
INSERT INTO xxl_job_group ( `app_name`, `title`, `address_type`, `address_list`, `update_time`) INSERT INTO xxl_job_group ( `app_name`, `title`, `address_type`, `address_list`, `access_token`, `update_time`)
values ( #{appname}, #{title}, #{addressType}, #{addressList}, #{updateTime} ); values ( #{appname}, #{title}, #{addressType}, #{addressList}, #{accessToken}, #{updateTime} );
</insert> </insert>
<update id="update" parameterType="com.xxl.job.admin.business.model.XxlJobGroup" > <update id="update" parameterType="com.xxl.job.admin.business.model.XxlJobGroup" >
@ -44,6 +46,7 @@
SET `title` = #{title}, SET `title` = #{title},
`address_type` = #{addressType}, `address_type` = #{addressType},
`address_list` = #{addressList}, `address_list` = #{addressList},
`access_token` = #{accessToken},
`update_time` = #{updateTime} `update_time` = #{updateTime}
WHERE id = #{id} WHERE id = #{id}
</update> </update>
@ -59,7 +62,7 @@
WHERE t.id = #{id} WHERE t.id = #{id}
</select> </select>
<select id="findByAppname" parameterType="java.lang.String" resultMap="XxlJobGroup"> <select id="loadByAppname" parameterType="java.lang.String" resultMap="XxlJobGroup">
SELECT <include refid="Base_Column_List" /> SELECT <include refid="Base_Column_List" />
FROM xxl_job_group AS t FROM xxl_job_group AS t
WHERE t.app_name = #{appname} WHERE t.app_name = #{appname}

@ -115,6 +115,10 @@
<textarea class="textarea" name="addressList" maxlength="20000" placeholder="${I18n.jobgroup_field_registryList_placeholder}" readonly="readonly" style="background-color:#eee; width: 100%; height: 100px; font-size: 14px; line-height: 15px; border: 1px solid #dddddd; padding: 5px;"></textarea> <textarea class="textarea" name="addressList" maxlength="20000" placeholder="${I18n.jobgroup_field_registryList_placeholder}" readonly="readonly" style="background-color:#eee; width: 100%; height: 100px; font-size: 14px; line-height: 15px; border: 1px solid #dddddd; padding: 5px;"></textarea>
</div> </div>
</div> </div>
<div class="form-group">
<label for="lastname" class="col-sm-2 control-label">AccessToken<font color="red">*</font></label>
<div class="col-sm-10"><input type="text" class="form-control" name="accessToken" placeholder="${I18n.system_please_input}AccessToken" maxlength="50" ></div>
</div>
<hr> <hr>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-4 col-sm-4"> <div class="col-sm-offset-4 col-sm-4">
@ -159,6 +163,10 @@
<textarea class="textarea" name="addressList" maxlength="20000" placeholder="${I18n.jobgroup_field_registryList_placeholder}" readonly="readonly" style="background-color:#eee; width: 100%; height: 100px; font-size: 14px; line-height: 15px; border: 1px solid #dddddd; padding: 5px;"></textarea> <textarea class="textarea" name="addressList" maxlength="20000" placeholder="${I18n.jobgroup_field_registryList_placeholder}" readonly="readonly" style="background-color:#eee; width: 100%; height: 100px; font-size: 14px; line-height: 15px; border: 1px solid #dddddd; padding: 5px;"></textarea>
</div> </div>
</div> </div>
<div class="form-group">
<label for="lastname" class="col-sm-2 control-label">AccessToken<font color="red">*</font></label>
<div class="col-sm-10"><input type="text" class="form-control" name="accessToken" placeholder="${I18n.system_please_input}AccessToken" maxlength="50" ></div>
</div>
<hr> <hr>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-4 col-sm-4"> <div class="col-sm-offset-4 col-sm-4">
@ -213,14 +221,20 @@
},{ },{
title: 'AppName', title: 'AppName',
field: 'appname', field: 'appname',
width: '30', width: '25',
widthUnit: '%', widthUnit: '%',
align: 'left' align: 'left'
},{ },{
title: I18n.jobgroup_field_title, title: I18n.jobgroup_field_title,
field: 'title', field: 'title',
width: '30', width: '25',
widthUnit: '%' widthUnit: '%'
},{
title: 'AccessToken',
field: 'accessToken',
width: '20',
widthUnit: '%',
align: 'left'
},{ },{
title: I18n.jobgroup_field_addressType, title: I18n.jobgroup_field_addressType,
field: 'addressType', field: 'addressType',
@ -278,33 +292,46 @@
* init add * init add
*/ */
// add validator method // add validator method
jQuery.validator.addMethod("myValid01", function(value, element) { jQuery.validator.addMethod("appnameValid", function(value, element) {
var length = value.length; var length = value.length;
var valid = /^[a-z][a-zA-Z0-9-]*$/; var valid = /^[a-z][a-zA-Z0-9-]*$/;
return this.optional(element) || valid.test(value); return this.optional(element) || valid.test(value);
}, I18n.jobgroup_field_appname_limit ); }, I18n.jobgroup_field_appname_limit );
// add validator method
jQuery.validator.addMethod("accessTokenValid", function(value, element) {
var valid = /^[a-z][a-z0-9]*$/;
return this.optional(element) || valid.test(value);
}, I18n.jobgroup_field_accesstoken_limit );
$.adminTable.initAdd( { $.adminTable.initAdd( {
url: base_url + "/jobgroup/insert", url: base_url + "/jobgroup/insert",
rules : { rules : {
appname : { appname : {
required : true, required : true,
rangelength:[4,64], rangelength:[4,64],
myValid01 : true appnameValid : true
}, },
title : { title : {
required : true, required : true,
rangelength:[4, 64] rangelength:[4, 64]
},
accessToken : {
required : true,
rangelength:[4, 50],
accessTokenValid: true
} }
}, },
messages : { messages : {
appname : { appname : {
required : I18n.system_please_input+"AppName", required : I18n.system_please_input+"AppName",
rangelength: I18n.jobgroup_field_appname_length , rangelength: I18n.system_length_limit + ' [4~64]'
myValid01: I18n.jobgroup_field_appname_limit
}, },
title : { title : {
required : I18n.system_please_input + I18n.jobgroup_field_title , required : I18n.system_please_input + I18n.jobgroup_field_title ,
rangelength: I18n.jobgroup_field_title_length rangelength: I18n.system_length_limit + ' [4~12]' ,
},
accessToken : {
required : I18n.system_please_input,
rangelength: I18n.system_length_limit + " [4-50]"
} }
}, },
writeFormData: function() { writeFormData: function() {
@ -346,28 +373,29 @@
$("#updateModal .form input[name='addressType'][value='"+ row.addressType +"']").click(); $("#updateModal .form input[name='addressType'][value='"+ row.addressType +"']").click();
// 机器地址 // 机器地址
$("#updateModal .form textarea[name='addressList']").val( row.addressList ); $("#updateModal .form textarea[name='addressList']").val( row.addressList );
// accessToken
$("#updateModal .form input[name='accessToken']").val( row.accessToken );
}, },
rules : { rules : {
appname : {
required : true,
rangelength:[4,64],
myValid01 : true
},
title : { title : {
required : true, required : true,
rangelength:[4, 64] rangelength:[4, 64]
},
accessToken : {
required : false,
rangelength:[4, 50],
accessTokenValid: true
} }
}, },
messages : { messages : {
appname : {
required : I18n.system_please_input+"AppName",
rangelength: I18n.jobgroup_field_appname_length ,
myValid01: I18n.jobgroup_field_appname_limit
},
title : { title : {
required : I18n.system_please_input + I18n.jobgroup_field_title , required : I18n.system_please_input + I18n.jobgroup_field_title ,
rangelength: I18n.jobgroup_field_title_length rangelength: I18n.system_length_limit + ' [4~12]'
},
accessToken : {
required : I18n.system_please_input,
rangelength: I18n.system_lengh_limit + " [4-50]"
} }
}, },
readFormData: function() { readFormData: function() {

@ -232,7 +232,7 @@
layer.open({ layer.open({
title: I18n.system_tips , title: I18n.system_tips ,
btn: [ I18n.system_ok ], btn: [ I18n.system_ok ],
content: I18n.jobinfo_glue_remark_limit , content: I18n.system_length_limit + ' [4-100]' ,
icon: '2' icon: '2'
}); });
return; return;

Loading…
Cancel
Save