diff --git a/README.md b/README.md index 3d56311c..7b0f1fe8 100644 --- a/README.md +++ b/README.md @@ -825,8 +825,8 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段 - 8、升级quartz版本至2.3.0; #### 6.15 版本 V1.7.2 特性(Coding) -- 1、阻塞处理机制:单机串行(默认)、并行、丢弃、覆盖; -- 2、失败处理机制;失败告警(默认)、失败重试; +- 1、阻塞处理策略:调度过于密集执行器来不及处理时的处理策略,策略包括:单机串行(默认)、丢弃后续调度、覆盖之前调度; +- 2、失败处理策略;调度失败时的处理策略,策略包括:失败告警(默认)、失败重试; #### TODO LIST - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限; diff --git a/db/tables_xxl_job.sql b/db/tables_xxl_job.sql index 7c9abcd3..0bafc29c 100644 --- a/db/tables_xxl_job.sql +++ b/db/tables_xxl_job.sql @@ -157,6 +157,8 @@ CREATE TABLE `XXL_JOB_QRTZ_TRIGGER_INFO` ( `executor_route_strategy` varchar(50) DEFAULT NULL COMMENT '执行器路由策略', `executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler', `executor_param` varchar(255) DEFAULT NULL COMMENT '执行器任务参数', + `executor_block_strategy` varchar(50) DEFAULT NULL COMMENT '阻塞处理策略', + `executor_fail_strategy` varchar(50) DEFAULT NULL COMMENT '失败处理策略', `glue_type` varchar(50) NOT NULL COMMENT 'GLUE类型', `glue_source` text COMMENT 'GLUE源代码', `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注', diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java index c5b4a2b8..9eb62c4f 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java @@ -1,11 +1,13 @@ package com.xxl.job.admin.controller; +import com.xxl.job.admin.core.enums.ExecutorFailStrategyEnum; import com.xxl.job.admin.core.model.XxlJobGroup; import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum; import com.xxl.job.admin.dao.IXxlJobGroupDao; import com.xxl.job.admin.service.IXxlJobService; import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; import com.xxl.job.core.glue.GlueTypeEnum; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -33,11 +35,11 @@ public class JobInfoController { @RequestMapping public String index(Model model) { - // 路由策略-列表 - model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values()); - - // Glue类型-字典 - model.addAttribute("GlueTypeEnum", GlueTypeEnum.values()); + // 枚举-字典 + model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values()); // 路由策略-列表 + model.addAttribute("GlueTypeEnum", GlueTypeEnum.values()); // Glue类型-字典 + model.addAttribute("ExecutorBlockStrategyEnum", ExecutorBlockStrategyEnum.values()); // 阻塞处理策略-字典 + model.addAttribute("ExecutorFailStrategyEnum", ExecutorFailStrategyEnum.values()); // 失败处理策略-字典 // 任务组 List jobGroupList = xxlJobGroupDao.findAll(); diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/enums/ExecutorFailStrategyEnum.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/enums/ExecutorFailStrategyEnum.java new file mode 100644 index 00000000..ea715233 --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/enums/ExecutorFailStrategyEnum.java @@ -0,0 +1,32 @@ +package com.xxl.job.admin.core.enums; + +/** + * Created by xuxueli on 17/5/9. + */ +public enum ExecutorFailStrategyEnum { + + FAIL_ALARM("失败告警"), + + FAIL_RETRY("失败重试"); + + private final String title; + private ExecutorFailStrategyEnum(String title) { + this.title = title; + } + + public String getTitle() { + return title; + } + + public static ExecutorFailStrategyEnum match(String name, ExecutorFailStrategyEnum defaultItem) { + if (name != null) { + for (ExecutorFailStrategyEnum item: ExecutorFailStrategyEnum.values()) { + if (item.name().equals(name)) { + return item; + } + } + } + return defaultItem; + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java index 3b84c7dd..ec1138d6 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java @@ -23,6 +23,8 @@ public class XxlJobInfo { private String executorRouteStrategy; // 执行器路由策略 private String executorHandler; // 执行器,任务Handler名称 private String executorParam; // 执行器,任务参数 + private String executorBlockStrategy; // 阻塞处理策略 + private String executorFailStrategy; // 失败处理策略 private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnum private String glueSource; // GLUE源代码 @@ -122,6 +124,22 @@ public class XxlJobInfo { this.executorParam = executorParam; } + public String getExecutorBlockStrategy() { + return executorBlockStrategy; + } + + public void setExecutorBlockStrategy(String executorBlockStrategy) { + this.executorBlockStrategy = executorBlockStrategy; + } + + public String getExecutorFailStrategy() { + return executorFailStrategy; + } + + public void setExecutorFailStrategy(String executorFailStrategy) { + this.executorFailStrategy = executorFailStrategy; + } + public String getGlueType() { return glueType; } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java index 19cbac97..1f606472 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java @@ -1,5 +1,6 @@ package com.xxl.job.admin.service.impl; +import com.xxl.job.admin.core.enums.ExecutorFailStrategyEnum; import com.xxl.job.admin.core.model.XxlJobGroup; import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum; @@ -8,6 +9,7 @@ import com.xxl.job.admin.core.thread.JobRegistryHelper; import com.xxl.job.admin.dao.*; import com.xxl.job.admin.service.IXxlJobService; import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; import com.xxl.job.core.glue.GlueTypeEnum; import com.xxl.job.core.registry.RegistHelper; import org.apache.commons.collections.CollectionUtils; @@ -68,25 +70,31 @@ public class XxlJobServiceImpl implements IXxlJobService { // valid XxlJobGroup group = xxlJobGroupDao.load(jobInfo.getJobGroup()); if (group == null) { - return new ReturnT(500, "请选择“执行器”"); + return new ReturnT(ReturnT.FAIL_CODE, "请选择“执行器”"); } if (!CronExpression.isValidExpression(jobInfo.getJobCron())) { - return new ReturnT(500, "请输入格式正确的“Cron”"); + return new ReturnT(ReturnT.FAIL_CODE, "请输入格式正确的“Cron”"); } if (StringUtils.isBlank(jobInfo.getJobDesc())) { - return new ReturnT(500, "请输入“任务描述”"); + return new ReturnT(ReturnT.FAIL_CODE, "请输入“任务描述”"); } if (StringUtils.isBlank(jobInfo.getAuthor())) { - return new ReturnT(500, "请输入“负责人”"); + return new ReturnT(ReturnT.FAIL_CODE, "请输入“负责人”"); } if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) { - return new ReturnT(500, "路由策略非法"); + return new ReturnT(ReturnT.FAIL_CODE, "路由策略非法"); + } + if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) { + return new ReturnT(ReturnT.FAIL_CODE, "阻塞处理策略非法"); + } + if (ExecutorFailStrategyEnum.match(jobInfo.getExecutorFailStrategy(), null) == null) { + return new ReturnT(ReturnT.FAIL_CODE, "失败处理策略非法"); } if (GlueTypeEnum.match(jobInfo.getGlueType()) == null) { - return new ReturnT(500, "运行模式非法非法"); + return new ReturnT(ReturnT.FAIL_CODE, "运行模式非法非法"); } if (GlueTypeEnum.BEAN==GlueTypeEnum.match(jobInfo.getGlueType()) && StringUtils.isBlank(jobInfo.getExecutorHandler())) { - return new ReturnT(500, "请输入“JobHandler”"); + return new ReturnT(ReturnT.FAIL_CODE, "请输入“JobHandler”"); } // fix "\r" in shell @@ -100,11 +108,11 @@ public class XxlJobServiceImpl implements IXxlJobService { for (String childJobKeyItem: childJobKeys) { String[] childJobKeyArr = childJobKeyItem.split("_"); if (childJobKeyArr.length!=2) { - return new ReturnT(500, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem)); + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem)); } XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobKeyArr[1])); if (childJobInfo==null) { - return new ReturnT(500, MessageFormat.format("子任务Key({0})无效", childJobKeyItem)); + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})无效", childJobKeyItem)); } } } @@ -112,7 +120,7 @@ public class XxlJobServiceImpl implements IXxlJobService { // add in db xxlJobInfoDao.save(jobInfo); if (jobInfo.getId() < 1) { - return new ReturnT(500, "新增任务失败"); + return new ReturnT(ReturnT.FAIL_CODE, "新增任务失败"); } // add in quartz @@ -130,7 +138,7 @@ public class XxlJobServiceImpl implements IXxlJobService { } catch (SchedulerException e1) { logger.error("", e1); } - return new ReturnT(500, "新增任务失败:" + e.getMessage()); + return new ReturnT(ReturnT.FAIL_CODE, "新增任务失败:" + e.getMessage()); } } @@ -139,16 +147,22 @@ public class XxlJobServiceImpl implements IXxlJobService { // valid if (!CronExpression.isValidExpression(jobInfo.getJobCron())) { - return new ReturnT(500, "请输入格式正确的“Cron”"); + return new ReturnT(ReturnT.FAIL_CODE, "请输入格式正确的“Cron”"); } if (StringUtils.isBlank(jobInfo.getJobDesc())) { - return new ReturnT(500, "请输入“任务描述”"); + return new ReturnT(ReturnT.FAIL_CODE, "请输入“任务描述”"); } if (StringUtils.isBlank(jobInfo.getAuthor())) { - return new ReturnT(500, "请输入“负责人”"); + return new ReturnT(ReturnT.FAIL_CODE, "请输入“负责人”"); } if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) { - return new ReturnT(500, "路由策略非法"); + return new ReturnT(ReturnT.FAIL_CODE, "路由策略非法"); + } + if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) { + return new ReturnT(ReturnT.FAIL_CODE, "阻塞处理策略非法"); + } + if (ExecutorFailStrategyEnum.match(jobInfo.getExecutorFailStrategy(), null) == null) { + return new ReturnT(ReturnT.FAIL_CODE, "失败处理策略非法"); } // childJobKey valid @@ -157,11 +171,11 @@ public class XxlJobServiceImpl implements IXxlJobService { for (String childJobKeyItem: childJobKeys) { String[] childJobKeyArr = childJobKeyItem.split("_"); if (childJobKeyArr.length!=2) { - return new ReturnT(500, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem)); + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem)); } XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobKeyArr[1])); if (childJobInfo==null) { - return new ReturnT(500, MessageFormat.format("子任务Key({0})无效", childJobKeyItem)); + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})无效", childJobKeyItem)); } } } @@ -170,7 +184,7 @@ public class XxlJobServiceImpl implements IXxlJobService { XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(jobInfo.getId()); String old_cron = exists_jobInfo.getJobCron(); if (exists_jobInfo == null) { - return new ReturnT(500, "参数异常"); + return new ReturnT(ReturnT.FAIL_CODE, "参数异常"); } exists_jobInfo.setJobCron(jobInfo.getJobCron()); @@ -180,6 +194,8 @@ public class XxlJobServiceImpl implements IXxlJobService { exists_jobInfo.setExecutorRouteStrategy(jobInfo.getExecutorRouteStrategy()); exists_jobInfo.setExecutorHandler(jobInfo.getExecutorHandler()); exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam()); + exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy()); + exists_jobInfo.setExecutorFailStrategy(jobInfo.getExecutorFailStrategy()); exists_jobInfo.setChildJobKey(jobInfo.getChildJobKey()); xxlJobInfoDao.update(exists_jobInfo); diff --git a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml index 0b97c308..9b16cce7 100644 --- a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml +++ b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml @@ -19,6 +19,8 @@ + + @@ -40,6 +42,8 @@ t.executor_route_strategy, t.executor_handler, t.executor_param, + t.executor_block_strategy, + t.executor_fail_strategy, t.glue_type, t.glue_source, t.glue_remark, @@ -87,7 +91,9 @@ executor_route_strategy, executor_handler, executor_param, - glue_type, + executor_block_strategy, + executor_fail_strategy, + glue_type, glue_source, glue_remark, glue_updatetime, @@ -103,6 +109,8 @@ #{executorRouteStrategy}, #{executorHandler}, #{executorParam}, + #{executorBlockStrategy}, + #{executorFailStrategy}, #{glueType}, #{glueSource}, #{glueRemark}, @@ -132,6 +140,8 @@ executor_route_strategy = #{executorRouteStrategy}, executor_handler = #{executorHandler}, executor_param = #{executorParam}, + executor_block_strategy = #{executorBlockStrategy}, + executor_fail_strategy = #{executorFailStrategy}, glue_type = #{glueType}, glue_source = #{glueSource}, glue_remark = #{glueRemark}, diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/jobinfo.index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/jobinfo.index.ftl index 25928a0d..1d61544e 100644 --- a/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/jobinfo.index.ftl +++ b/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/jobinfo.index.ftl @@ -152,6 +152,24 @@
+ +
+ +
+ +
+ +
+ +
@@ -279,6 +297,24 @@ logging.info("脚本文件:" + sys.argv[0])
+
+ +
+ +
+ +
+ +
+
diff --git a/xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js b/xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js index 8f446a17..72922944 100644 --- a/xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js +++ b/xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js @@ -118,18 +118,8 @@ $(function() { } // html - var html = '

'+ + tableData['key'+row.id] = row; + var html = '

'+ ' '+ pause_resume + '
'+ @@ -168,7 +158,10 @@ $(function() { } } }); - + + // table data + var tableData = {}; + // 搜索按钮 $('#searchBtn').on('click', function(){ jobTable.fnDraw(); @@ -347,19 +340,31 @@ $(function() { // 更新 $("#job_list").on('click', '.update',function() { - // base data - $("#updateModal .form input[name='id']").val($(this).parent('p').attr("id")); - $('#updateModal .form select[name=jobGroup] option[value='+ $(this).parent('p').attr("jobGroup") +']').prop('selected', true); - $("#updateModal .form input[name='jobDesc']").val($(this).parent('p').attr("jobDesc")); - $("#updateModal .form input[name='jobCron']").val($(this).parent('p').attr("jobCron")); - $("#updateModal .form input[name='author']").val($(this).parent('p').attr("author")); - $("#updateModal .form input[name='alarmEmail']").val($(this).parent('p').attr("alarmEmail")); - $('#updateModal .form select[name=executorRouteStrategy] option[value='+ $(this).parent('p').attr("executorRouteStrategy") +']').prop('selected', true); - $("#updateModal .form input[name='executorHandler']").val($(this).parent('p').attr("executorHandler")); - $("#updateModal .form input[name='executorParam']").val($(this).parent('p').attr("executorParam")); - $("#updateModal .form input[name='childJobKey']").val($(this).parent('p').attr("childJobKey")); - $('#updateModal .form select[name=glueType] option[value='+ $(this).parent('p').attr("glueType") +']').prop('selected', true); + var id = $(this).parent('p').attr("id"); + var row = tableData['key'+id]; + if (!row) { + layer.open({ + title: '系统提示', + content: ("任务信息加载失败,请刷新页面"), + icon: '2' + }); + return; + } + // base data + $("#updateModal .form input[name='id']").val( row.id ); + $('#updateModal .form select[name=jobGroup] option[value='+ row.jobGroup +']').prop('selected', true); + $("#updateModal .form input[name='jobDesc']").val( row.jobDesc ); + $("#updateModal .form input[name='jobCron']").val( row.jobCron ); + $("#updateModal .form input[name='author']").val( row.author ); + $("#updateModal .form input[name='alarmEmail']").val( row.alarmEmail ); + $('#updateModal .form select[name=executorRouteStrategy] option[value='+ row.executorRouteStrategy +']').prop('selected', true); + $("#updateModal .form input[name='executorHandler']").val( row.executorHandler ); + $("#updateModal .form input[name='executorParam']").val( row.executorParam ); + $("#updateModal .form input[name='childJobKey']").val( row.childJobKey ); + $('#updateModal .form select[name=executorBlockStrategy] option[value='+ row.executorBlockStrategy +']').prop('selected', true); + $('#updateModal .form select[name=executorFailStrategy] option[value='+ row.executorFailStrategy +']').prop('selected', true); + $('#updateModal .form select[name=glueType] option[value='+ row.glueType +']').prop('selected', true); $("#updateModal .form select[name=glueType]").change(); diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/enums/ExecutorBlockStrategyEnum.java b/xxl-job-core/src/main/java/com/xxl/job/core/enums/ExecutorBlockStrategyEnum.java new file mode 100644 index 00000000..0b340365 --- /dev/null +++ b/xxl-job-core/src/main/java/com/xxl/job/core/enums/ExecutorBlockStrategyEnum.java @@ -0,0 +1,31 @@ +package com.xxl.job.core.enums; + +/** + * Created by xuxueli on 17/5/9. + */ +public enum ExecutorBlockStrategyEnum { + + SERIAL_EXECUTION("单机串行"), + /*CONCURRENT_EXECUTION("并行"),*/ + DISCARD_LATER("丢弃后续调度"), + COVER_EARLY("覆盖之前调度"); + + private final String title; + private ExecutorBlockStrategyEnum (String title) { + this.title = title; + } + public String getTitle() { + return title; + } + + public static ExecutorBlockStrategyEnum match(String name, ExecutorBlockStrategyEnum defaultItem) { + if (name != null) { + for (ExecutorBlockStrategyEnum item:ExecutorBlockStrategyEnum.values()) { + if (item.name().equals(name)) { + return item; + } + } + } + return defaultItem; + } +}