diff --git "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" index 1e5e198..d2aaa47 100644 --- "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" +++ "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" @@ -374,7 +374,7 @@ GLUE模式(Python):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "python" 脚本; GLUE模式(NodeJS):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "nodejs" 脚本; - JobHandler:运行模式为 "BEAN模式" 时生效,对应执行器中新开发的JobHandler类“@JobHandler”注解自定义的value值; - - 子任务Key:每个任务都拥有一个唯一的任务Key(任务Key可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务Key所对应的任务的一次主动调度。 + - 子任务:每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务ID所对应的任务的一次主动调度。 - 阻塞处理策略:调度过于密集执行器来不及处理时的处理策略; 单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行; 丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败; @@ -699,7 +699,7 @@ #### 5.4.9 调度日志 调度中心每次进行任务调度,都会记录一条任务日志,任务日志主要包括以下三部分内容: -- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击JobKey可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; +- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击任务ID按钮可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; - 调度信息:包括“调度时间”、“调度结果”和“调度日志”等,根据这些参数,可以了解“调度中心”发起调度请求时具体情况。 - 执行信息:包括“执行时间”、“执行结果”和“执行日志”等,根据这些参数,可以了解在“执行器”端任务执行的具体情况; @@ -716,9 +716,9 @@ - 执行日志:任务执行过程中,业务代码中打印的完整执行日志,见“4.7 查看执行日志”; #### 5.4.10 任务依赖 -原理:XXL-JOB中每个任务都对应有一个任务Key,同时,每个任务支持设置属性“子任务Key”,因此,通过“任务Key”可以匹配任务依赖关系。 +原理:XXL-JOB中每个任务都对应有一个任务ID,同时,每个任务支持设置属性“子任务ID”,因此,通过“任务ID”可以匹配任务依赖关系。 -当父任务执行结束并且执行成功时,将会根据“子任务Key”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 +当父任务执行结束并且执行成功时,将会根据“子任务ID”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 在任务日志界面,点击任务的“执行备注”的“查看”按钮,可以看到匹配子任务以及触发子任务执行的日志信息,如无信息则表示未触发子任务执行,可参考下图。 @@ -1102,7 +1102,8 @@ - 25、底层系统日志级别规范调整,清理遗留代码; - 26、建表SQL优化,支持同步创建制定编码的库和表; - 27、系统安全性优化,登陆Token写Cookie时进行MD5加密,同时Cookie启用HttpOnly; - +- 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。 +- 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环; ### TODO LIST - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限; @@ -1118,6 +1119,7 @@ - 11、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件; - 12、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性; - 13、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发; +- 14、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题; ## 七、其他 diff --git "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" index 1e5e198..d2aaa47 100644 --- "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" +++ "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" @@ -374,7 +374,7 @@ GLUE模式(Python):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "python" 脚本; GLUE模式(NodeJS):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "nodejs" 脚本; - JobHandler:运行模式为 "BEAN模式" 时生效,对应执行器中新开发的JobHandler类“@JobHandler”注解自定义的value值; - - 子任务Key:每个任务都拥有一个唯一的任务Key(任务Key可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务Key所对应的任务的一次主动调度。 + - 子任务:每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务ID所对应的任务的一次主动调度。 - 阻塞处理策略:调度过于密集执行器来不及处理时的处理策略; 单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行; 丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败; @@ -699,7 +699,7 @@ #### 5.4.9 调度日志 调度中心每次进行任务调度,都会记录一条任务日志,任务日志主要包括以下三部分内容: -- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击JobKey可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; +- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击任务ID按钮可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; - 调度信息:包括“调度时间”、“调度结果”和“调度日志”等,根据这些参数,可以了解“调度中心”发起调度请求时具体情况。 - 执行信息:包括“执行时间”、“执行结果”和“执行日志”等,根据这些参数,可以了解在“执行器”端任务执行的具体情况; @@ -716,9 +716,9 @@ - 执行日志:任务执行过程中,业务代码中打印的完整执行日志,见“4.7 查看执行日志”; #### 5.4.10 任务依赖 -原理:XXL-JOB中每个任务都对应有一个任务Key,同时,每个任务支持设置属性“子任务Key”,因此,通过“任务Key”可以匹配任务依赖关系。 +原理:XXL-JOB中每个任务都对应有一个任务ID,同时,每个任务支持设置属性“子任务ID”,因此,通过“任务ID”可以匹配任务依赖关系。 -当父任务执行结束并且执行成功时,将会根据“子任务Key”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 +当父任务执行结束并且执行成功时,将会根据“子任务ID”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 在任务日志界面,点击任务的“执行备注”的“查看”按钮,可以看到匹配子任务以及触发子任务执行的日志信息,如无信息则表示未触发子任务执行,可参考下图。 @@ -1102,7 +1102,8 @@ - 25、底层系统日志级别规范调整,清理遗留代码; - 26、建表SQL优化,支持同步创建制定编码的库和表; - 27、系统安全性优化,登陆Token写Cookie时进行MD5加密,同时Cookie启用HttpOnly; - +- 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。 +- 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环; ### TODO LIST - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限; @@ -1118,6 +1119,7 @@ - 11、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件; - 12、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性; - 13、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发; +- 14、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题; ## 七、其他 diff --git a/doc/db/tables_xxl_job.sql b/doc/db/tables_xxl_job.sql index 6de1918..ed32895 100644 --- a/doc/db/tables_xxl_job.sql +++ b/doc/db/tables_xxl_job.sql @@ -167,7 +167,7 @@ `glue_source` text COMMENT 'GLUE源代码', `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注', `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间', - `child_jobkey` varchar(255) DEFAULT NULL COMMENT '子任务Key', + `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" index 1e5e198..d2aaa47 100644 --- "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" +++ "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" @@ -374,7 +374,7 @@ GLUE模式(Python):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "python" 脚本; GLUE模式(NodeJS):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "nodejs" 脚本; - JobHandler:运行模式为 "BEAN模式" 时生效,对应执行器中新开发的JobHandler类“@JobHandler”注解自定义的value值; - - 子任务Key:每个任务都拥有一个唯一的任务Key(任务Key可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务Key所对应的任务的一次主动调度。 + - 子任务:每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务ID所对应的任务的一次主动调度。 - 阻塞处理策略:调度过于密集执行器来不及处理时的处理策略; 单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行; 丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败; @@ -699,7 +699,7 @@ #### 5.4.9 调度日志 调度中心每次进行任务调度,都会记录一条任务日志,任务日志主要包括以下三部分内容: -- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击JobKey可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; +- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击任务ID按钮可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; - 调度信息:包括“调度时间”、“调度结果”和“调度日志”等,根据这些参数,可以了解“调度中心”发起调度请求时具体情况。 - 执行信息:包括“执行时间”、“执行结果”和“执行日志”等,根据这些参数,可以了解在“执行器”端任务执行的具体情况; @@ -716,9 +716,9 @@ - 执行日志:任务执行过程中,业务代码中打印的完整执行日志,见“4.7 查看执行日志”; #### 5.4.10 任务依赖 -原理:XXL-JOB中每个任务都对应有一个任务Key,同时,每个任务支持设置属性“子任务Key”,因此,通过“任务Key”可以匹配任务依赖关系。 +原理:XXL-JOB中每个任务都对应有一个任务ID,同时,每个任务支持设置属性“子任务ID”,因此,通过“任务ID”可以匹配任务依赖关系。 -当父任务执行结束并且执行成功时,将会根据“子任务Key”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 +当父任务执行结束并且执行成功时,将会根据“子任务ID”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 在任务日志界面,点击任务的“执行备注”的“查看”按钮,可以看到匹配子任务以及触发子任务执行的日志信息,如无信息则表示未触发子任务执行,可参考下图。 @@ -1102,7 +1102,8 @@ - 25、底层系统日志级别规范调整,清理遗留代码; - 26、建表SQL优化,支持同步创建制定编码的库和表; - 27、系统安全性优化,登陆Token写Cookie时进行MD5加密,同时Cookie启用HttpOnly; - +- 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。 +- 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环; ### TODO LIST - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限; @@ -1118,6 +1119,7 @@ - 11、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件; - 12、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性; - 13、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发; +- 14、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题; ## 七、其他 diff --git a/doc/db/tables_xxl_job.sql b/doc/db/tables_xxl_job.sql index 6de1918..ed32895 100644 --- a/doc/db/tables_xxl_job.sql +++ b/doc/db/tables_xxl_job.sql @@ -167,7 +167,7 @@ `glue_source` text COMMENT 'GLUE源代码', `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注', `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间', - `child_jobkey` varchar(255) DEFAULT NULL COMMENT '子任务Key', + `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 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 ec1138d..51847ac 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 @@ -31,7 +31,7 @@ private String glueRemark; // GLUE备注 private Date glueUpdatetime; // GLUE更新时间 - private String childJobKey; // 子任务Key + private String childJobId; // 子任务ID,多个逗号分隔 // copy from quartz private String jobStatus; // 任务状态 【base on quartz】 @@ -172,12 +172,12 @@ this.glueUpdatetime = glueUpdatetime; } - public String getChildJobKey() { - return childJobKey; + public String getChildJobId() { + return childJobId; } - public void setChildJobKey(String childJobKey) { - this.childJobKey = childJobKey; + public void setChildJobId(String childJobId) { + this.childJobId = childJobId; } public String getJobStatus() { diff --git "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" index 1e5e198..d2aaa47 100644 --- "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" +++ "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" @@ -374,7 +374,7 @@ GLUE模式(Python):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "python" 脚本; GLUE模式(NodeJS):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "nodejs" 脚本; - JobHandler:运行模式为 "BEAN模式" 时生效,对应执行器中新开发的JobHandler类“@JobHandler”注解自定义的value值; - - 子任务Key:每个任务都拥有一个唯一的任务Key(任务Key可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务Key所对应的任务的一次主动调度。 + - 子任务:每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务ID所对应的任务的一次主动调度。 - 阻塞处理策略:调度过于密集执行器来不及处理时的处理策略; 单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行; 丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败; @@ -699,7 +699,7 @@ #### 5.4.9 调度日志 调度中心每次进行任务调度,都会记录一条任务日志,任务日志主要包括以下三部分内容: -- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击JobKey可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; +- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击任务ID按钮可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; - 调度信息:包括“调度时间”、“调度结果”和“调度日志”等,根据这些参数,可以了解“调度中心”发起调度请求时具体情况。 - 执行信息:包括“执行时间”、“执行结果”和“执行日志”等,根据这些参数,可以了解在“执行器”端任务执行的具体情况; @@ -716,9 +716,9 @@ - 执行日志:任务执行过程中,业务代码中打印的完整执行日志,见“4.7 查看执行日志”; #### 5.4.10 任务依赖 -原理:XXL-JOB中每个任务都对应有一个任务Key,同时,每个任务支持设置属性“子任务Key”,因此,通过“任务Key”可以匹配任务依赖关系。 +原理:XXL-JOB中每个任务都对应有一个任务ID,同时,每个任务支持设置属性“子任务ID”,因此,通过“任务ID”可以匹配任务依赖关系。 -当父任务执行结束并且执行成功时,将会根据“子任务Key”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 +当父任务执行结束并且执行成功时,将会根据“子任务ID”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 在任务日志界面,点击任务的“执行备注”的“查看”按钮,可以看到匹配子任务以及触发子任务执行的日志信息,如无信息则表示未触发子任务执行,可参考下图。 @@ -1102,7 +1102,8 @@ - 25、底层系统日志级别规范调整,清理遗留代码; - 26、建表SQL优化,支持同步创建制定编码的库和表; - 27、系统安全性优化,登陆Token写Cookie时进行MD5加密,同时Cookie启用HttpOnly; - +- 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。 +- 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环; ### TODO LIST - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限; @@ -1118,6 +1119,7 @@ - 11、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件; - 12、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性; - 13、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发; +- 14、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题; ## 七、其他 diff --git a/doc/db/tables_xxl_job.sql b/doc/db/tables_xxl_job.sql index 6de1918..ed32895 100644 --- a/doc/db/tables_xxl_job.sql +++ b/doc/db/tables_xxl_job.sql @@ -167,7 +167,7 @@ `glue_source` text COMMENT 'GLUE源代码', `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注', `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间', - `child_jobkey` varchar(255) DEFAULT NULL COMMENT '子任务Key', + `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 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 ec1138d..51847ac 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 @@ -31,7 +31,7 @@ private String glueRemark; // GLUE备注 private Date glueUpdatetime; // GLUE更新时间 - private String childJobKey; // 子任务Key + private String childJobId; // 子任务ID,多个逗号分隔 // copy from quartz private String jobStatus; // 任务状态 【base on quartz】 @@ -172,12 +172,12 @@ this.glueUpdatetime = glueUpdatetime; } - public String getChildJobKey() { - return childJobKey; + public String getChildJobId() { + return childJobId; } - public void setChildJobKey(String childJobKey) { - this.childJobKey = childJobKey; + public void setChildJobId(String childJobId) { + this.childJobId = childJobId; } public String getJobStatus() { diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java index 2695569..c9f7f04 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java @@ -4,7 +4,6 @@ import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobLog; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.core.util.MailUtil; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; @@ -125,7 +124,7 @@ " " + " \n" + " 执行器\n" + - " JobKey\n" + + " 任务ID\n" + " 任务描述\n" + " 告警类型\n" + " \n" + @@ -156,7 +155,7 @@ XxlJobGroup group = XxlJobDynamicScheduler.xxlJobGroupDao.load(Integer.valueOf(info.getJobGroup())); String title = "调度中心监控报警"; - String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", JobKeyUtil.formatJobKey(info), info.getJobDesc()); + String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", info.getId(), info.getJobDesc()); MailUtil.sendMail(email, title, content); } diff --git "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" index 1e5e198..d2aaa47 100644 --- "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" +++ "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" @@ -374,7 +374,7 @@ GLUE模式(Python):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "python" 脚本; GLUE模式(NodeJS):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "nodejs" 脚本; - JobHandler:运行模式为 "BEAN模式" 时生效,对应执行器中新开发的JobHandler类“@JobHandler”注解自定义的value值; - - 子任务Key:每个任务都拥有一个唯一的任务Key(任务Key可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务Key所对应的任务的一次主动调度。 + - 子任务:每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务ID所对应的任务的一次主动调度。 - 阻塞处理策略:调度过于密集执行器来不及处理时的处理策略; 单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行; 丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败; @@ -699,7 +699,7 @@ #### 5.4.9 调度日志 调度中心每次进行任务调度,都会记录一条任务日志,任务日志主要包括以下三部分内容: -- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击JobKey可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; +- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击任务ID按钮可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; - 调度信息:包括“调度时间”、“调度结果”和“调度日志”等,根据这些参数,可以了解“调度中心”发起调度请求时具体情况。 - 执行信息:包括“执行时间”、“执行结果”和“执行日志”等,根据这些参数,可以了解在“执行器”端任务执行的具体情况; @@ -716,9 +716,9 @@ - 执行日志:任务执行过程中,业务代码中打印的完整执行日志,见“4.7 查看执行日志”; #### 5.4.10 任务依赖 -原理:XXL-JOB中每个任务都对应有一个任务Key,同时,每个任务支持设置属性“子任务Key”,因此,通过“任务Key”可以匹配任务依赖关系。 +原理:XXL-JOB中每个任务都对应有一个任务ID,同时,每个任务支持设置属性“子任务ID”,因此,通过“任务ID”可以匹配任务依赖关系。 -当父任务执行结束并且执行成功时,将会根据“子任务Key”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 +当父任务执行结束并且执行成功时,将会根据“子任务ID”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 在任务日志界面,点击任务的“执行备注”的“查看”按钮,可以看到匹配子任务以及触发子任务执行的日志信息,如无信息则表示未触发子任务执行,可参考下图。 @@ -1102,7 +1102,8 @@ - 25、底层系统日志级别规范调整,清理遗留代码; - 26、建表SQL优化,支持同步创建制定编码的库和表; - 27、系统安全性优化,登陆Token写Cookie时进行MD5加密,同时Cookie启用HttpOnly; - +- 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。 +- 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环; ### TODO LIST - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限; @@ -1118,6 +1119,7 @@ - 11、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件; - 12、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性; - 13、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发; +- 14、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题; ## 七、其他 diff --git a/doc/db/tables_xxl_job.sql b/doc/db/tables_xxl_job.sql index 6de1918..ed32895 100644 --- a/doc/db/tables_xxl_job.sql +++ b/doc/db/tables_xxl_job.sql @@ -167,7 +167,7 @@ `glue_source` text COMMENT 'GLUE源代码', `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注', `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间', - `child_jobkey` varchar(255) DEFAULT NULL COMMENT '子任务Key', + `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 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 ec1138d..51847ac 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 @@ -31,7 +31,7 @@ private String glueRemark; // GLUE备注 private Date glueUpdatetime; // GLUE更新时间 - private String childJobKey; // 子任务Key + private String childJobId; // 子任务ID,多个逗号分隔 // copy from quartz private String jobStatus; // 任务状态 【base on quartz】 @@ -172,12 +172,12 @@ this.glueUpdatetime = glueUpdatetime; } - public String getChildJobKey() { - return childJobKey; + public String getChildJobId() { + return childJobId; } - public void setChildJobKey(String childJobKey) { - this.childJobKey = childJobKey; + public void setChildJobId(String childJobId) { + this.childJobId = childJobId; } public String getJobStatus() { diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java index 2695569..c9f7f04 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java @@ -4,7 +4,6 @@ import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobLog; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.core.util.MailUtil; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; @@ -125,7 +124,7 @@ " " + " \n" + " 执行器\n" + - " JobKey\n" + + " 任务ID\n" + " 任务描述\n" + " 告警类型\n" + " \n" + @@ -156,7 +155,7 @@ XxlJobGroup group = XxlJobDynamicScheduler.xxlJobGroupDao.load(Integer.valueOf(info.getJobGroup())); String title = "调度中心监控报警"; - String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", JobKeyUtil.formatJobKey(info), info.getJobDesc()); + String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", info.getId(), info.getJobDesc()); MailUtil.sendMail(email, title, content); } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java deleted file mode 100644 index 7eaea1f..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.xxl.job.admin.core.util; - -import com.xxl.job.admin.core.model.XxlJobInfo; -import org.apache.commons.lang3.StringUtils; - -/** - * job key util - * - * @author xuxueli 2017-12-22 18:48:45 - */ -public class JobKeyUtil { - - /** - * format job key - * - * @param xxlJobInfo - * @return - */ - public static String formatJobKey(XxlJobInfo xxlJobInfo){ - return String.valueOf(xxlJobInfo.getJobGroup()) - .concat("_").concat(String.valueOf(xxlJobInfo.getId())); - } - - /** - * parse jobId from JobKey - * - * @param jobKey - * @return - */ - public static int parseJobId(String jobKey){ - if (jobKey!=null && jobKey.trim().length()>0) { - String[] jobKeyArr = jobKey.split("_"); - if (jobKeyArr.length == 2) { - String jobIdStr = jobKeyArr[1]; - if (StringUtils.isNotBlank(jobIdStr) && StringUtils.isNumeric(jobIdStr)) { - int jobId = Integer.valueOf(jobIdStr); - return jobId; - } - } - } - return -1; - } - -} diff --git "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" index 1e5e198..d2aaa47 100644 --- "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" +++ "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" @@ -374,7 +374,7 @@ GLUE模式(Python):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "python" 脚本; GLUE模式(NodeJS):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "nodejs" 脚本; - JobHandler:运行模式为 "BEAN模式" 时生效,对应执行器中新开发的JobHandler类“@JobHandler”注解自定义的value值; - - 子任务Key:每个任务都拥有一个唯一的任务Key(任务Key可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务Key所对应的任务的一次主动调度。 + - 子任务:每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务ID所对应的任务的一次主动调度。 - 阻塞处理策略:调度过于密集执行器来不及处理时的处理策略; 单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行; 丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败; @@ -699,7 +699,7 @@ #### 5.4.9 调度日志 调度中心每次进行任务调度,都会记录一条任务日志,任务日志主要包括以下三部分内容: -- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击JobKey可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; +- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击任务ID按钮可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; - 调度信息:包括“调度时间”、“调度结果”和“调度日志”等,根据这些参数,可以了解“调度中心”发起调度请求时具体情况。 - 执行信息:包括“执行时间”、“执行结果”和“执行日志”等,根据这些参数,可以了解在“执行器”端任务执行的具体情况; @@ -716,9 +716,9 @@ - 执行日志:任务执行过程中,业务代码中打印的完整执行日志,见“4.7 查看执行日志”; #### 5.4.10 任务依赖 -原理:XXL-JOB中每个任务都对应有一个任务Key,同时,每个任务支持设置属性“子任务Key”,因此,通过“任务Key”可以匹配任务依赖关系。 +原理:XXL-JOB中每个任务都对应有一个任务ID,同时,每个任务支持设置属性“子任务ID”,因此,通过“任务ID”可以匹配任务依赖关系。 -当父任务执行结束并且执行成功时,将会根据“子任务Key”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 +当父任务执行结束并且执行成功时,将会根据“子任务ID”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 在任务日志界面,点击任务的“执行备注”的“查看”按钮,可以看到匹配子任务以及触发子任务执行的日志信息,如无信息则表示未触发子任务执行,可参考下图。 @@ -1102,7 +1102,8 @@ - 25、底层系统日志级别规范调整,清理遗留代码; - 26、建表SQL优化,支持同步创建制定编码的库和表; - 27、系统安全性优化,登陆Token写Cookie时进行MD5加密,同时Cookie启用HttpOnly; - +- 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。 +- 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环; ### TODO LIST - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限; @@ -1118,6 +1119,7 @@ - 11、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件; - 12、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性; - 13、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发; +- 14、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题; ## 七、其他 diff --git a/doc/db/tables_xxl_job.sql b/doc/db/tables_xxl_job.sql index 6de1918..ed32895 100644 --- a/doc/db/tables_xxl_job.sql +++ b/doc/db/tables_xxl_job.sql @@ -167,7 +167,7 @@ `glue_source` text COMMENT 'GLUE源代码', `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注', `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间', - `child_jobkey` varchar(255) DEFAULT NULL COMMENT '子任务Key', + `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 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 ec1138d..51847ac 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 @@ -31,7 +31,7 @@ private String glueRemark; // GLUE备注 private Date glueUpdatetime; // GLUE更新时间 - private String childJobKey; // 子任务Key + private String childJobId; // 子任务ID,多个逗号分隔 // copy from quartz private String jobStatus; // 任务状态 【base on quartz】 @@ -172,12 +172,12 @@ this.glueUpdatetime = glueUpdatetime; } - public String getChildJobKey() { - return childJobKey; + public String getChildJobId() { + return childJobId; } - public void setChildJobKey(String childJobKey) { - this.childJobKey = childJobKey; + public void setChildJobId(String childJobId) { + this.childJobId = childJobId; } public String getJobStatus() { diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java index 2695569..c9f7f04 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java @@ -4,7 +4,6 @@ import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobLog; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.core.util.MailUtil; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; @@ -125,7 +124,7 @@ " " + " \n" + " 执行器\n" + - " JobKey\n" + + " 任务ID\n" + " 任务描述\n" + " 告警类型\n" + " \n" + @@ -156,7 +155,7 @@ XxlJobGroup group = XxlJobDynamicScheduler.xxlJobGroupDao.load(Integer.valueOf(info.getJobGroup())); String title = "调度中心监控报警"; - String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", JobKeyUtil.formatJobKey(info), info.getJobDesc()); + String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", info.getId(), info.getJobDesc()); MailUtil.sendMail(email, title, content); } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java deleted file mode 100644 index 7eaea1f..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.xxl.job.admin.core.util; - -import com.xxl.job.admin.core.model.XxlJobInfo; -import org.apache.commons.lang3.StringUtils; - -/** - * job key util - * - * @author xuxueli 2017-12-22 18:48:45 - */ -public class JobKeyUtil { - - /** - * format job key - * - * @param xxlJobInfo - * @return - */ - public static String formatJobKey(XxlJobInfo xxlJobInfo){ - return String.valueOf(xxlJobInfo.getJobGroup()) - .concat("_").concat(String.valueOf(xxlJobInfo.getId())); - } - - /** - * parse jobId from JobKey - * - * @param jobKey - * @return - */ - public static int parseJobId(String jobKey){ - if (jobKey!=null && jobKey.trim().length()>0) { - String[] jobKeyArr = jobKey.split("_"); - if (jobKeyArr.length == 2) { - String jobIdStr = jobKeyArr[1]; - if (StringUtils.isNotBlank(jobIdStr) && StringUtils.isNumeric(jobIdStr)) { - int jobId = Integer.valueOf(jobIdStr); - return jobId; - } - } - } - return -1; - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java index 6f989b8..352b4c9 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java @@ -1,11 +1,7 @@ package com.xxl.job.admin.service.impl; -import com.xxl.job.admin.controller.JobApiController; import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobLog; -import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.trigger.XxlJobTrigger; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobLogDao; import com.xxl.job.admin.dao.XxlJobRegistryDao; @@ -16,7 +12,6 @@ import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; import org.apache.commons.lang3.StringUtils; -import org.quartz.SchedulerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -68,21 +63,21 @@ String callbackMsg = null; if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) { XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId()); - if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobKey())) { + if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobId())) { callbackMsg = "

>>>>>>>>>>>触发子任务<<<<<<<<<<<
"; - String[] childJobKeys = xxlJobInfo.getChildJobKey().split(","); - for (int i = 0; i < childJobKeys.length; i++) { - int childJobId = JobKeyUtil.parseJobId(childJobKeys[i]); + String[] childJobIds = xxlJobInfo.getChildJobId().split(","); + for (int i = 0; i < childJobIds.length; i++) { + int childJobId = (StringUtils.isNotBlank(childJobIds[i]) && StringUtils.isNumeric(childJobIds[i]))?Integer.valueOf(childJobIds[i]):-1; if (childJobId > 0) { ReturnT triggerChildResult = xxlJobService.triggerJob(childJobId); // add msg - callbackMsg += MessageFormat.format("{0}/{1} [JobKey={2}], 触发{3}, 触发备注: {4}
", - (i+1), childJobKeys.length, childJobKeys[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg()); + callbackMsg += MessageFormat.format("{0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4}
", + (i+1), childJobIds.length, childJobIds[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg()); } else { - callbackMsg += MessageFormat.format(" {0}/{1} [JobKey={2}], 触发失败, 触发备注: JobKey格式错误
", - (i+1), childJobKeys.length, childJobKeys[i]); + callbackMsg += MessageFormat.format(" {0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误
", + (i+1), childJobIds.length, childJobIds[i]); } } diff --git "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" index 1e5e198..d2aaa47 100644 --- "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" +++ "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" @@ -374,7 +374,7 @@ GLUE模式(Python):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "python" 脚本; GLUE模式(NodeJS):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "nodejs" 脚本; - JobHandler:运行模式为 "BEAN模式" 时生效,对应执行器中新开发的JobHandler类“@JobHandler”注解自定义的value值; - - 子任务Key:每个任务都拥有一个唯一的任务Key(任务Key可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务Key所对应的任务的一次主动调度。 + - 子任务:每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务ID所对应的任务的一次主动调度。 - 阻塞处理策略:调度过于密集执行器来不及处理时的处理策略; 单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行; 丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败; @@ -699,7 +699,7 @@ #### 5.4.9 调度日志 调度中心每次进行任务调度,都会记录一条任务日志,任务日志主要包括以下三部分内容: -- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击JobKey可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; +- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击任务ID按钮可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; - 调度信息:包括“调度时间”、“调度结果”和“调度日志”等,根据这些参数,可以了解“调度中心”发起调度请求时具体情况。 - 执行信息:包括“执行时间”、“执行结果”和“执行日志”等,根据这些参数,可以了解在“执行器”端任务执行的具体情况; @@ -716,9 +716,9 @@ - 执行日志:任务执行过程中,业务代码中打印的完整执行日志,见“4.7 查看执行日志”; #### 5.4.10 任务依赖 -原理:XXL-JOB中每个任务都对应有一个任务Key,同时,每个任务支持设置属性“子任务Key”,因此,通过“任务Key”可以匹配任务依赖关系。 +原理:XXL-JOB中每个任务都对应有一个任务ID,同时,每个任务支持设置属性“子任务ID”,因此,通过“任务ID”可以匹配任务依赖关系。 -当父任务执行结束并且执行成功时,将会根据“子任务Key”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 +当父任务执行结束并且执行成功时,将会根据“子任务ID”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 在任务日志界面,点击任务的“执行备注”的“查看”按钮,可以看到匹配子任务以及触发子任务执行的日志信息,如无信息则表示未触发子任务执行,可参考下图。 @@ -1102,7 +1102,8 @@ - 25、底层系统日志级别规范调整,清理遗留代码; - 26、建表SQL优化,支持同步创建制定编码的库和表; - 27、系统安全性优化,登陆Token写Cookie时进行MD5加密,同时Cookie启用HttpOnly; - +- 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。 +- 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环; ### TODO LIST - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限; @@ -1118,6 +1119,7 @@ - 11、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件; - 12、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性; - 13、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发; +- 14、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题; ## 七、其他 diff --git a/doc/db/tables_xxl_job.sql b/doc/db/tables_xxl_job.sql index 6de1918..ed32895 100644 --- a/doc/db/tables_xxl_job.sql +++ b/doc/db/tables_xxl_job.sql @@ -167,7 +167,7 @@ `glue_source` text COMMENT 'GLUE源代码', `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注', `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间', - `child_jobkey` varchar(255) DEFAULT NULL COMMENT '子任务Key', + `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 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 ec1138d..51847ac 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 @@ -31,7 +31,7 @@ private String glueRemark; // GLUE备注 private Date glueUpdatetime; // GLUE更新时间 - private String childJobKey; // 子任务Key + private String childJobId; // 子任务ID,多个逗号分隔 // copy from quartz private String jobStatus; // 任务状态 【base on quartz】 @@ -172,12 +172,12 @@ this.glueUpdatetime = glueUpdatetime; } - public String getChildJobKey() { - return childJobKey; + public String getChildJobId() { + return childJobId; } - public void setChildJobKey(String childJobKey) { - this.childJobKey = childJobKey; + public void setChildJobId(String childJobId) { + this.childJobId = childJobId; } public String getJobStatus() { diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java index 2695569..c9f7f04 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java @@ -4,7 +4,6 @@ import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobLog; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.core.util.MailUtil; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; @@ -125,7 +124,7 @@ " " + " \n" + " 执行器\n" + - " JobKey\n" + + " 任务ID\n" + " 任务描述\n" + " 告警类型\n" + " \n" + @@ -156,7 +155,7 @@ XxlJobGroup group = XxlJobDynamicScheduler.xxlJobGroupDao.load(Integer.valueOf(info.getJobGroup())); String title = "调度中心监控报警"; - String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", JobKeyUtil.formatJobKey(info), info.getJobDesc()); + String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", info.getId(), info.getJobDesc()); MailUtil.sendMail(email, title, content); } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java deleted file mode 100644 index 7eaea1f..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.xxl.job.admin.core.util; - -import com.xxl.job.admin.core.model.XxlJobInfo; -import org.apache.commons.lang3.StringUtils; - -/** - * job key util - * - * @author xuxueli 2017-12-22 18:48:45 - */ -public class JobKeyUtil { - - /** - * format job key - * - * @param xxlJobInfo - * @return - */ - public static String formatJobKey(XxlJobInfo xxlJobInfo){ - return String.valueOf(xxlJobInfo.getJobGroup()) - .concat("_").concat(String.valueOf(xxlJobInfo.getId())); - } - - /** - * parse jobId from JobKey - * - * @param jobKey - * @return - */ - public static int parseJobId(String jobKey){ - if (jobKey!=null && jobKey.trim().length()>0) { - String[] jobKeyArr = jobKey.split("_"); - if (jobKeyArr.length == 2) { - String jobIdStr = jobKeyArr[1]; - if (StringUtils.isNotBlank(jobIdStr) && StringUtils.isNumeric(jobIdStr)) { - int jobId = Integer.valueOf(jobIdStr); - return jobId; - } - } - } - return -1; - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java index 6f989b8..352b4c9 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java @@ -1,11 +1,7 @@ package com.xxl.job.admin.service.impl; -import com.xxl.job.admin.controller.JobApiController; import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobLog; -import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.trigger.XxlJobTrigger; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobLogDao; import com.xxl.job.admin.dao.XxlJobRegistryDao; @@ -16,7 +12,6 @@ import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; import org.apache.commons.lang3.StringUtils; -import org.quartz.SchedulerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -68,21 +63,21 @@ String callbackMsg = null; if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) { XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId()); - if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobKey())) { + if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobId())) { callbackMsg = "

>>>>>>>>>>>触发子任务<<<<<<<<<<<
"; - String[] childJobKeys = xxlJobInfo.getChildJobKey().split(","); - for (int i = 0; i < childJobKeys.length; i++) { - int childJobId = JobKeyUtil.parseJobId(childJobKeys[i]); + String[] childJobIds = xxlJobInfo.getChildJobId().split(","); + for (int i = 0; i < childJobIds.length; i++) { + int childJobId = (StringUtils.isNotBlank(childJobIds[i]) && StringUtils.isNumeric(childJobIds[i]))?Integer.valueOf(childJobIds[i]):-1; if (childJobId > 0) { ReturnT triggerChildResult = xxlJobService.triggerJob(childJobId); // add msg - callbackMsg += MessageFormat.format("{0}/{1} [JobKey={2}], 触发{3}, 触发备注: {4}
", - (i+1), childJobKeys.length, childJobKeys[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg()); + callbackMsg += MessageFormat.format("{0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4}
", + (i+1), childJobIds.length, childJobIds[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg()); } else { - callbackMsg += MessageFormat.format(" {0}/{1} [JobKey={2}], 触发失败, 触发备注: JobKey格式错误
", - (i+1), childJobKeys.length, childJobKeys[i]); + callbackMsg += MessageFormat.format(" {0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误
", + (i+1), childJobIds.length, childJobIds[i]); } } 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 820e896..eecef34 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 @@ -5,7 +5,6 @@ import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.dao.XxlJobGroupDao; import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobLogDao; @@ -104,19 +103,20 @@ jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", "")); } - // childJobKey valid - if (StringUtils.isNotBlank(jobInfo.getChildJobKey())) { - String[] childJobKeys = jobInfo.getChildJobKey().split(","); - for (String childJobKeyItem: childJobKeys) { - int childJobId = JobKeyUtil.parseJobId(childJobKeyItem); - if (childJobId <= 0) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem)); - } - XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(childJobId); - if (childJobInfo==null) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})无效", childJobKeyItem)); + // ChildJobId valid + if (StringUtils.isNotBlank(jobInfo.getChildJobId())) { + String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ","); + for (String childJobIdItem: childJobIds) { + if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) { + XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem)); + if (childJobInfo==null) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem)); + } + } else { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem)); } } + jobInfo.setChildJobId(StringUtils.join(childJobIds, ",")); } // add in db @@ -167,19 +167,24 @@ return new ReturnT(ReturnT.FAIL_CODE, "失败处理策略非法"); } - // childJobKey valid - if (StringUtils.isNotBlank(jobInfo.getChildJobKey())) { - String[] childJobKeys = jobInfo.getChildJobKey().split(","); - for (String childJobKeyItem: childJobKeys) { - int childJobId = JobKeyUtil.parseJobId(childJobKeyItem); - if (childJobId <= 0) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem)); - } - XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(childJobId); - if (childJobInfo==null) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})无效", childJobKeyItem)); + // ChildJobId valid + if (StringUtils.isNotBlank(jobInfo.getChildJobId())) { + String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ","); + for (String childJobIdItem: childJobIds) { + if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) { + XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem)); + if (childJobInfo==null) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem)); + } + // avoid cycle relate + if (childJobInfo.getId() == jobInfo.getId()) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})不可与父任务重复", childJobIdItem)); + } + } else { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem)); } } + jobInfo.setChildJobId(StringUtils.join(childJobIds, ",")); } // stage job info @@ -198,7 +203,7 @@ exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam()); exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy()); exists_jobInfo.setExecutorFailStrategy(jobInfo.getExecutorFailStrategy()); - exists_jobInfo.setChildJobKey(jobInfo.getChildJobKey()); + exists_jobInfo.setChildJobId(jobInfo.getChildJobId()); xxlJobInfoDao.update(exists_jobInfo); // fresh quartz diff --git "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" index 1e5e198..d2aaa47 100644 --- "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" +++ "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" @@ -374,7 +374,7 @@ GLUE模式(Python):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "python" 脚本; GLUE模式(NodeJS):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "nodejs" 脚本; - JobHandler:运行模式为 "BEAN模式" 时生效,对应执行器中新开发的JobHandler类“@JobHandler”注解自定义的value值; - - 子任务Key:每个任务都拥有一个唯一的任务Key(任务Key可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务Key所对应的任务的一次主动调度。 + - 子任务:每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务ID所对应的任务的一次主动调度。 - 阻塞处理策略:调度过于密集执行器来不及处理时的处理策略; 单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行; 丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败; @@ -699,7 +699,7 @@ #### 5.4.9 调度日志 调度中心每次进行任务调度,都会记录一条任务日志,任务日志主要包括以下三部分内容: -- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击JobKey可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; +- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击任务ID按钮可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; - 调度信息:包括“调度时间”、“调度结果”和“调度日志”等,根据这些参数,可以了解“调度中心”发起调度请求时具体情况。 - 执行信息:包括“执行时间”、“执行结果”和“执行日志”等,根据这些参数,可以了解在“执行器”端任务执行的具体情况; @@ -716,9 +716,9 @@ - 执行日志:任务执行过程中,业务代码中打印的完整执行日志,见“4.7 查看执行日志”; #### 5.4.10 任务依赖 -原理:XXL-JOB中每个任务都对应有一个任务Key,同时,每个任务支持设置属性“子任务Key”,因此,通过“任务Key”可以匹配任务依赖关系。 +原理:XXL-JOB中每个任务都对应有一个任务ID,同时,每个任务支持设置属性“子任务ID”,因此,通过“任务ID”可以匹配任务依赖关系。 -当父任务执行结束并且执行成功时,将会根据“子任务Key”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 +当父任务执行结束并且执行成功时,将会根据“子任务ID”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 在任务日志界面,点击任务的“执行备注”的“查看”按钮,可以看到匹配子任务以及触发子任务执行的日志信息,如无信息则表示未触发子任务执行,可参考下图。 @@ -1102,7 +1102,8 @@ - 25、底层系统日志级别规范调整,清理遗留代码; - 26、建表SQL优化,支持同步创建制定编码的库和表; - 27、系统安全性优化,登陆Token写Cookie时进行MD5加密,同时Cookie启用HttpOnly; - +- 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。 +- 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环; ### TODO LIST - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限; @@ -1118,6 +1119,7 @@ - 11、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件; - 12、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性; - 13、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发; +- 14、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题; ## 七、其他 diff --git a/doc/db/tables_xxl_job.sql b/doc/db/tables_xxl_job.sql index 6de1918..ed32895 100644 --- a/doc/db/tables_xxl_job.sql +++ b/doc/db/tables_xxl_job.sql @@ -167,7 +167,7 @@ `glue_source` text COMMENT 'GLUE源代码', `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注', `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间', - `child_jobkey` varchar(255) DEFAULT NULL COMMENT '子任务Key', + `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 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 ec1138d..51847ac 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 @@ -31,7 +31,7 @@ private String glueRemark; // GLUE备注 private Date glueUpdatetime; // GLUE更新时间 - private String childJobKey; // 子任务Key + private String childJobId; // 子任务ID,多个逗号分隔 // copy from quartz private String jobStatus; // 任务状态 【base on quartz】 @@ -172,12 +172,12 @@ this.glueUpdatetime = glueUpdatetime; } - public String getChildJobKey() { - return childJobKey; + public String getChildJobId() { + return childJobId; } - public void setChildJobKey(String childJobKey) { - this.childJobKey = childJobKey; + public void setChildJobId(String childJobId) { + this.childJobId = childJobId; } public String getJobStatus() { diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java index 2695569..c9f7f04 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java @@ -4,7 +4,6 @@ import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobLog; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.core.util.MailUtil; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; @@ -125,7 +124,7 @@ " " + " \n" + " 执行器\n" + - " JobKey\n" + + " 任务ID\n" + " 任务描述\n" + " 告警类型\n" + " \n" + @@ -156,7 +155,7 @@ XxlJobGroup group = XxlJobDynamicScheduler.xxlJobGroupDao.load(Integer.valueOf(info.getJobGroup())); String title = "调度中心监控报警"; - String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", JobKeyUtil.formatJobKey(info), info.getJobDesc()); + String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", info.getId(), info.getJobDesc()); MailUtil.sendMail(email, title, content); } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java deleted file mode 100644 index 7eaea1f..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.xxl.job.admin.core.util; - -import com.xxl.job.admin.core.model.XxlJobInfo; -import org.apache.commons.lang3.StringUtils; - -/** - * job key util - * - * @author xuxueli 2017-12-22 18:48:45 - */ -public class JobKeyUtil { - - /** - * format job key - * - * @param xxlJobInfo - * @return - */ - public static String formatJobKey(XxlJobInfo xxlJobInfo){ - return String.valueOf(xxlJobInfo.getJobGroup()) - .concat("_").concat(String.valueOf(xxlJobInfo.getId())); - } - - /** - * parse jobId from JobKey - * - * @param jobKey - * @return - */ - public static int parseJobId(String jobKey){ - if (jobKey!=null && jobKey.trim().length()>0) { - String[] jobKeyArr = jobKey.split("_"); - if (jobKeyArr.length == 2) { - String jobIdStr = jobKeyArr[1]; - if (StringUtils.isNotBlank(jobIdStr) && StringUtils.isNumeric(jobIdStr)) { - int jobId = Integer.valueOf(jobIdStr); - return jobId; - } - } - } - return -1; - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java index 6f989b8..352b4c9 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java @@ -1,11 +1,7 @@ package com.xxl.job.admin.service.impl; -import com.xxl.job.admin.controller.JobApiController; import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobLog; -import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.trigger.XxlJobTrigger; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobLogDao; import com.xxl.job.admin.dao.XxlJobRegistryDao; @@ -16,7 +12,6 @@ import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; import org.apache.commons.lang3.StringUtils; -import org.quartz.SchedulerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -68,21 +63,21 @@ String callbackMsg = null; if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) { XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId()); - if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobKey())) { + if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobId())) { callbackMsg = "

>>>>>>>>>>>触发子任务<<<<<<<<<<<
"; - String[] childJobKeys = xxlJobInfo.getChildJobKey().split(","); - for (int i = 0; i < childJobKeys.length; i++) { - int childJobId = JobKeyUtil.parseJobId(childJobKeys[i]); + String[] childJobIds = xxlJobInfo.getChildJobId().split(","); + for (int i = 0; i < childJobIds.length; i++) { + int childJobId = (StringUtils.isNotBlank(childJobIds[i]) && StringUtils.isNumeric(childJobIds[i]))?Integer.valueOf(childJobIds[i]):-1; if (childJobId > 0) { ReturnT triggerChildResult = xxlJobService.triggerJob(childJobId); // add msg - callbackMsg += MessageFormat.format("{0}/{1} [JobKey={2}], 触发{3}, 触发备注: {4}
", - (i+1), childJobKeys.length, childJobKeys[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg()); + callbackMsg += MessageFormat.format("{0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4}
", + (i+1), childJobIds.length, childJobIds[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg()); } else { - callbackMsg += MessageFormat.format(" {0}/{1} [JobKey={2}], 触发失败, 触发备注: JobKey格式错误
", - (i+1), childJobKeys.length, childJobKeys[i]); + callbackMsg += MessageFormat.format(" {0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误
", + (i+1), childJobIds.length, childJobIds[i]); } } 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 820e896..eecef34 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 @@ -5,7 +5,6 @@ import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.dao.XxlJobGroupDao; import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobLogDao; @@ -104,19 +103,20 @@ jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", "")); } - // childJobKey valid - if (StringUtils.isNotBlank(jobInfo.getChildJobKey())) { - String[] childJobKeys = jobInfo.getChildJobKey().split(","); - for (String childJobKeyItem: childJobKeys) { - int childJobId = JobKeyUtil.parseJobId(childJobKeyItem); - if (childJobId <= 0) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem)); - } - XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(childJobId); - if (childJobInfo==null) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})无效", childJobKeyItem)); + // ChildJobId valid + if (StringUtils.isNotBlank(jobInfo.getChildJobId())) { + String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ","); + for (String childJobIdItem: childJobIds) { + if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) { + XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem)); + if (childJobInfo==null) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem)); + } + } else { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem)); } } + jobInfo.setChildJobId(StringUtils.join(childJobIds, ",")); } // add in db @@ -167,19 +167,24 @@ return new ReturnT(ReturnT.FAIL_CODE, "失败处理策略非法"); } - // childJobKey valid - if (StringUtils.isNotBlank(jobInfo.getChildJobKey())) { - String[] childJobKeys = jobInfo.getChildJobKey().split(","); - for (String childJobKeyItem: childJobKeys) { - int childJobId = JobKeyUtil.parseJobId(childJobKeyItem); - if (childJobId <= 0) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem)); - } - XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(childJobId); - if (childJobInfo==null) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})无效", childJobKeyItem)); + // ChildJobId valid + if (StringUtils.isNotBlank(jobInfo.getChildJobId())) { + String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ","); + for (String childJobIdItem: childJobIds) { + if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) { + XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem)); + if (childJobInfo==null) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem)); + } + // avoid cycle relate + if (childJobInfo.getId() == jobInfo.getId()) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})不可与父任务重复", childJobIdItem)); + } + } else { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem)); } } + jobInfo.setChildJobId(StringUtils.join(childJobIds, ",")); } // stage job info @@ -198,7 +203,7 @@ exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam()); exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy()); exists_jobInfo.setExecutorFailStrategy(jobInfo.getExecutorFailStrategy()); - exists_jobInfo.setChildJobKey(jobInfo.getChildJobKey()); + exists_jobInfo.setChildJobId(jobInfo.getChildJobId()); xxlJobInfoDao.update(exists_jobInfo); // fresh quartz 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 9be9b8e..a5c3abd 100644 --- a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml +++ b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml @@ -27,7 +27,7 @@ - + @@ -48,7 +48,7 @@ t.glue_source, t.glue_remark, t.glue_updatetime, - t.child_jobkey + t.child_jobid @@ -97,7 +97,7 @@ glue_source, glue_remark, glue_updatetime, - child_jobkey + child_jobid ) VALUES ( #{jobGroup}, #{jobCron}, @@ -115,7 +115,7 @@ #{glueSource}, #{glueRemark}, NOW(), - #{childJobKey} + #{childJobId} ); 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 eccd6ca..74d88fc 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 @@ -20,7 +20,7 @@ "ordering": false, //"scrollX": true, // X轴滚动条,取消自适应 "columns": [ - { "data": 'id', "bSortable": false, "visible" : false}, + { "data": 'id', "bSortable": false, "visible" : true}, { "data": 'jobGroup', "visible" : false, @@ -34,15 +34,6 @@ return data; } }, - { - "data": 'childJobKey', - "width":'10%', - "visible" : true, - "render": function ( data, type, row ) { - var jobKey = row.jobGroup + "_" + row.id; - return jobKey; - } - }, { "data": 'jobDesc', "visible" : true,"width":'20%'}, { "data": 'glueType', @@ -372,7 +363,7 @@ $('#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 input[name='childJobId']").val( row.childJobId ); $('#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); diff --git "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" index 1e5e198..d2aaa47 100644 --- "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" +++ "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" @@ -374,7 +374,7 @@ GLUE模式(Python):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "python" 脚本; GLUE模式(NodeJS):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "nodejs" 脚本; - JobHandler:运行模式为 "BEAN模式" 时生效,对应执行器中新开发的JobHandler类“@JobHandler”注解自定义的value值; - - 子任务Key:每个任务都拥有一个唯一的任务Key(任务Key可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务Key所对应的任务的一次主动调度。 + - 子任务:每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务ID所对应的任务的一次主动调度。 - 阻塞处理策略:调度过于密集执行器来不及处理时的处理策略; 单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行; 丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败; @@ -699,7 +699,7 @@ #### 5.4.9 调度日志 调度中心每次进行任务调度,都会记录一条任务日志,任务日志主要包括以下三部分内容: -- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击JobKey可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; +- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击任务ID按钮可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; - 调度信息:包括“调度时间”、“调度结果”和“调度日志”等,根据这些参数,可以了解“调度中心”发起调度请求时具体情况。 - 执行信息:包括“执行时间”、“执行结果”和“执行日志”等,根据这些参数,可以了解在“执行器”端任务执行的具体情况; @@ -716,9 +716,9 @@ - 执行日志:任务执行过程中,业务代码中打印的完整执行日志,见“4.7 查看执行日志”; #### 5.4.10 任务依赖 -原理:XXL-JOB中每个任务都对应有一个任务Key,同时,每个任务支持设置属性“子任务Key”,因此,通过“任务Key”可以匹配任务依赖关系。 +原理:XXL-JOB中每个任务都对应有一个任务ID,同时,每个任务支持设置属性“子任务ID”,因此,通过“任务ID”可以匹配任务依赖关系。 -当父任务执行结束并且执行成功时,将会根据“子任务Key”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 +当父任务执行结束并且执行成功时,将会根据“子任务ID”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 在任务日志界面,点击任务的“执行备注”的“查看”按钮,可以看到匹配子任务以及触发子任务执行的日志信息,如无信息则表示未触发子任务执行,可参考下图。 @@ -1102,7 +1102,8 @@ - 25、底层系统日志级别规范调整,清理遗留代码; - 26、建表SQL优化,支持同步创建制定编码的库和表; - 27、系统安全性优化,登陆Token写Cookie时进行MD5加密,同时Cookie启用HttpOnly; - +- 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。 +- 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环; ### TODO LIST - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限; @@ -1118,6 +1119,7 @@ - 11、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件; - 12、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性; - 13、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发; +- 14、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题; ## 七、其他 diff --git a/doc/db/tables_xxl_job.sql b/doc/db/tables_xxl_job.sql index 6de1918..ed32895 100644 --- a/doc/db/tables_xxl_job.sql +++ b/doc/db/tables_xxl_job.sql @@ -167,7 +167,7 @@ `glue_source` text COMMENT 'GLUE源代码', `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注', `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间', - `child_jobkey` varchar(255) DEFAULT NULL COMMENT '子任务Key', + `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 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 ec1138d..51847ac 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 @@ -31,7 +31,7 @@ private String glueRemark; // GLUE备注 private Date glueUpdatetime; // GLUE更新时间 - private String childJobKey; // 子任务Key + private String childJobId; // 子任务ID,多个逗号分隔 // copy from quartz private String jobStatus; // 任务状态 【base on quartz】 @@ -172,12 +172,12 @@ this.glueUpdatetime = glueUpdatetime; } - public String getChildJobKey() { - return childJobKey; + public String getChildJobId() { + return childJobId; } - public void setChildJobKey(String childJobKey) { - this.childJobKey = childJobKey; + public void setChildJobId(String childJobId) { + this.childJobId = childJobId; } public String getJobStatus() { diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java index 2695569..c9f7f04 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java @@ -4,7 +4,6 @@ import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobLog; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.core.util.MailUtil; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; @@ -125,7 +124,7 @@ " " + " \n" + " 执行器\n" + - " JobKey\n" + + " 任务ID\n" + " 任务描述\n" + " 告警类型\n" + " \n" + @@ -156,7 +155,7 @@ XxlJobGroup group = XxlJobDynamicScheduler.xxlJobGroupDao.load(Integer.valueOf(info.getJobGroup())); String title = "调度中心监控报警"; - String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", JobKeyUtil.formatJobKey(info), info.getJobDesc()); + String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", info.getId(), info.getJobDesc()); MailUtil.sendMail(email, title, content); } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java deleted file mode 100644 index 7eaea1f..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.xxl.job.admin.core.util; - -import com.xxl.job.admin.core.model.XxlJobInfo; -import org.apache.commons.lang3.StringUtils; - -/** - * job key util - * - * @author xuxueli 2017-12-22 18:48:45 - */ -public class JobKeyUtil { - - /** - * format job key - * - * @param xxlJobInfo - * @return - */ - public static String formatJobKey(XxlJobInfo xxlJobInfo){ - return String.valueOf(xxlJobInfo.getJobGroup()) - .concat("_").concat(String.valueOf(xxlJobInfo.getId())); - } - - /** - * parse jobId from JobKey - * - * @param jobKey - * @return - */ - public static int parseJobId(String jobKey){ - if (jobKey!=null && jobKey.trim().length()>0) { - String[] jobKeyArr = jobKey.split("_"); - if (jobKeyArr.length == 2) { - String jobIdStr = jobKeyArr[1]; - if (StringUtils.isNotBlank(jobIdStr) && StringUtils.isNumeric(jobIdStr)) { - int jobId = Integer.valueOf(jobIdStr); - return jobId; - } - } - } - return -1; - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java index 6f989b8..352b4c9 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java @@ -1,11 +1,7 @@ package com.xxl.job.admin.service.impl; -import com.xxl.job.admin.controller.JobApiController; import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobLog; -import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.trigger.XxlJobTrigger; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobLogDao; import com.xxl.job.admin.dao.XxlJobRegistryDao; @@ -16,7 +12,6 @@ import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; import org.apache.commons.lang3.StringUtils; -import org.quartz.SchedulerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -68,21 +63,21 @@ String callbackMsg = null; if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) { XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId()); - if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobKey())) { + if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobId())) { callbackMsg = "

>>>>>>>>>>>触发子任务<<<<<<<<<<<
"; - String[] childJobKeys = xxlJobInfo.getChildJobKey().split(","); - for (int i = 0; i < childJobKeys.length; i++) { - int childJobId = JobKeyUtil.parseJobId(childJobKeys[i]); + String[] childJobIds = xxlJobInfo.getChildJobId().split(","); + for (int i = 0; i < childJobIds.length; i++) { + int childJobId = (StringUtils.isNotBlank(childJobIds[i]) && StringUtils.isNumeric(childJobIds[i]))?Integer.valueOf(childJobIds[i]):-1; if (childJobId > 0) { ReturnT triggerChildResult = xxlJobService.triggerJob(childJobId); // add msg - callbackMsg += MessageFormat.format("{0}/{1} [JobKey={2}], 触发{3}, 触发备注: {4}
", - (i+1), childJobKeys.length, childJobKeys[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg()); + callbackMsg += MessageFormat.format("{0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4}
", + (i+1), childJobIds.length, childJobIds[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg()); } else { - callbackMsg += MessageFormat.format(" {0}/{1} [JobKey={2}], 触发失败, 触发备注: JobKey格式错误
", - (i+1), childJobKeys.length, childJobKeys[i]); + callbackMsg += MessageFormat.format(" {0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误
", + (i+1), childJobIds.length, childJobIds[i]); } } 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 820e896..eecef34 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 @@ -5,7 +5,6 @@ import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.dao.XxlJobGroupDao; import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobLogDao; @@ -104,19 +103,20 @@ jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", "")); } - // childJobKey valid - if (StringUtils.isNotBlank(jobInfo.getChildJobKey())) { - String[] childJobKeys = jobInfo.getChildJobKey().split(","); - for (String childJobKeyItem: childJobKeys) { - int childJobId = JobKeyUtil.parseJobId(childJobKeyItem); - if (childJobId <= 0) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem)); - } - XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(childJobId); - if (childJobInfo==null) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})无效", childJobKeyItem)); + // ChildJobId valid + if (StringUtils.isNotBlank(jobInfo.getChildJobId())) { + String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ","); + for (String childJobIdItem: childJobIds) { + if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) { + XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem)); + if (childJobInfo==null) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem)); + } + } else { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem)); } } + jobInfo.setChildJobId(StringUtils.join(childJobIds, ",")); } // add in db @@ -167,19 +167,24 @@ return new ReturnT(ReturnT.FAIL_CODE, "失败处理策略非法"); } - // childJobKey valid - if (StringUtils.isNotBlank(jobInfo.getChildJobKey())) { - String[] childJobKeys = jobInfo.getChildJobKey().split(","); - for (String childJobKeyItem: childJobKeys) { - int childJobId = JobKeyUtil.parseJobId(childJobKeyItem); - if (childJobId <= 0) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem)); - } - XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(childJobId); - if (childJobInfo==null) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})无效", childJobKeyItem)); + // ChildJobId valid + if (StringUtils.isNotBlank(jobInfo.getChildJobId())) { + String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ","); + for (String childJobIdItem: childJobIds) { + if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) { + XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem)); + if (childJobInfo==null) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem)); + } + // avoid cycle relate + if (childJobInfo.getId() == jobInfo.getId()) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})不可与父任务重复", childJobIdItem)); + } + } else { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem)); } } + jobInfo.setChildJobId(StringUtils.join(childJobIds, ",")); } // stage job info @@ -198,7 +203,7 @@ exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam()); exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy()); exists_jobInfo.setExecutorFailStrategy(jobInfo.getExecutorFailStrategy()); - exists_jobInfo.setChildJobKey(jobInfo.getChildJobKey()); + exists_jobInfo.setChildJobId(jobInfo.getChildJobId()); xxlJobInfoDao.update(exists_jobInfo); // fresh quartz 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 9be9b8e..a5c3abd 100644 --- a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml +++ b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml @@ -27,7 +27,7 @@ - + @@ -48,7 +48,7 @@ t.glue_source, t.glue_remark, t.glue_updatetime, - t.child_jobkey + t.child_jobid @@ -97,7 +97,7 @@ glue_source, glue_remark, glue_updatetime, - child_jobkey + child_jobid ) VALUES ( #{jobGroup}, #{jobCron}, @@ -115,7 +115,7 @@ #{glueSource}, #{glueRemark}, NOW(), - #{childJobKey} + #{childJobId} ); 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 eccd6ca..74d88fc 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 @@ -20,7 +20,7 @@ "ordering": false, //"scrollX": true, // X轴滚动条,取消自适应 "columns": [ - { "data": 'id', "bSortable": false, "visible" : false}, + { "data": 'id', "bSortable": false, "visible" : true}, { "data": 'jobGroup', "visible" : false, @@ -34,15 +34,6 @@ return data; } }, - { - "data": 'childJobKey', - "width":'10%', - "visible" : true, - "render": function ( data, type, row ) { - var jobKey = row.jobGroup + "_" + row.id; - return jobKey; - } - }, { "data": 'jobDesc', "visible" : true,"width":'20%'}, { "data": 'glueType', @@ -372,7 +363,7 @@ $('#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 input[name='childJobId']").val( row.childJobId ); $('#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); diff --git a/xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js b/xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js index e9fecf0..fb7aa64 100644 --- a/xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js +++ b/xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js @@ -89,54 +89,32 @@ "ordering": false, //"scrollX": false, "columns": [ - { "data": 'id', "bSortable": false, "visible" : false}, - { "data": 'jobGroup', "visible" : false}, - { "data": 'jobId', "visible" : false}, { - "data": 'JobKey', + "data": 'jobId', "visible" : true, "render": function ( data, type, row ) { - var jobKey = row.jobGroup + "_" + row.jobId; + var glueTypeTitle = row.glueType; + if ('GLUE_GROOVY'==row.glueType) { + glueTypeTitle = "GLUE模式(Java)"; + } else if ('GLUE_SHELL'==row.glueType) { + glueTypeTitle = "GLUE模式(Shell)"; + } else if ('GLUE_PYTHON'==row.glueType) { + glueTypeTitle = "GLUE模式(Python)"; + }else if ('GLUE_NODEJS'==row.glueType) { + glueTypeTitle = "GLUE模式(Nodejs)"; + } else if ('BEAN'==row.glueType) { + glueTypeTitle = "BEAN模式:" + row.executorHandler; + } - var glueTypeTitle = row.glueType; - if ('GLUE_GROOVY'==row.glueType) { - glueTypeTitle = "GLUE模式(Java)"; - } else if ('GLUE_SHELL'==row.glueType) { - glueTypeTitle = "GLUE模式(Shell)"; - } else if ('GLUE_PYTHON'==row.glueType) { - glueTypeTitle = "GLUE模式(Python)"; - }else if ('GLUE_NODEJS'==row.glueType) { - glueTypeTitle = "GLUE模式(Nodejs)"; - } else if ('BEAN'==row.glueType) { - glueTypeTitle = "BEAN模式:" + row.executorHandler; - } + var temp = ''; + temp += '执行器地址:' + (row.executorAddress?row.executorAddress:''); + temp += '
运行模式:' + glueTypeTitle; + temp += '
任务参数:' + row.executorParam; - var temp = ''; - temp += '执行器地址:' + (row.executorAddress?row.executorAddress:''); - temp += '
运行模式:' + glueTypeTitle; - temp += '
任务参数:' + row.executorParam; - - return ''+ jobKey +''+ temp +''; + return ''+ row.jobId +''+ temp +''; } }, - // { "data": 'executorAddress', "visible" : true}, - // { - // "data": 'glueType', - // "visible" : true, - // "render": function ( data, type, row ) { - // if ('GLUE_GROOVY'==row.glueType) { - // return "GLUE模式(Java)"; - // } else if ('GLUE_SHELL'==row.glueType) { - // return "GLUE模式(Shell)"; - // } else if ('GLUE_PYTHON'==row.glueType) { - // return "GLUE模式(Python)"; - // } else if ('BEAN'==row.glueType) { - // return "BEAN模式:" + row.executorHandler; - // } - // return row.executorHandler; - // } - // }, - // { "data": 'executorParam', "visible" : true}, + { "data": 'jobGroup', "visible" : false}, { "data": 'triggerTime', "render": function ( data, type, row ) { diff --git a/xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobInfoDaoTest.java b/xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobInfoDaoTest.java index 5da58a1..87c4de9 100644 --- a/xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobInfoDaoTest.java +++ b/xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobInfoDaoTest.java @@ -45,7 +45,7 @@ info.setGlueType("setGlueType"); info.setGlueSource("setGlueSource"); info.setGlueRemark("setGlueRemark"); - info.setChildJobKey("setChildJobKey"); + info.setChildJobId("1"); int count = xxlJobInfoDao.save(info); @@ -63,7 +63,7 @@ info2.setGlueSource("setGlueSource2"); info2.setGlueRemark("setGlueRemark2"); info2.setGlueUpdatetime(new Date()); - info2.setChildJobKey("setChildJobKey2"); + info2.setChildJobId("1"); int item2 = xxlJobInfoDao.update(info2); diff --git "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" index 1e5e198..d2aaa47 100644 --- "a/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" +++ "b/doc/XXL-JOB\345\256\230\346\226\271\346\226\207\346\241\243.md" @@ -374,7 +374,7 @@ GLUE模式(Python):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "python" 脚本; GLUE模式(NodeJS):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "nodejs" 脚本; - JobHandler:运行模式为 "BEAN模式" 时生效,对应执行器中新开发的JobHandler类“@JobHandler”注解自定义的value值; - - 子任务Key:每个任务都拥有一个唯一的任务Key(任务Key可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务Key所对应的任务的一次主动调度。 + - 子任务:每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务ID所对应的任务的一次主动调度。 - 阻塞处理策略:调度过于密集执行器来不及处理时的处理策略; 单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行; 丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败; @@ -699,7 +699,7 @@ #### 5.4.9 调度日志 调度中心每次进行任务调度,都会记录一条任务日志,任务日志主要包括以下三部分内容: -- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击JobKey可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; +- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击任务ID按钮可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; - 调度信息:包括“调度时间”、“调度结果”和“调度日志”等,根据这些参数,可以了解“调度中心”发起调度请求时具体情况。 - 执行信息:包括“执行时间”、“执行结果”和“执行日志”等,根据这些参数,可以了解在“执行器”端任务执行的具体情况; @@ -716,9 +716,9 @@ - 执行日志:任务执行过程中,业务代码中打印的完整执行日志,见“4.7 查看执行日志”; #### 5.4.10 任务依赖 -原理:XXL-JOB中每个任务都对应有一个任务Key,同时,每个任务支持设置属性“子任务Key”,因此,通过“任务Key”可以匹配任务依赖关系。 +原理:XXL-JOB中每个任务都对应有一个任务ID,同时,每个任务支持设置属性“子任务ID”,因此,通过“任务ID”可以匹配任务依赖关系。 -当父任务执行结束并且执行成功时,将会根据“子任务Key”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 +当父任务执行结束并且执行成功时,将会根据“子任务ID”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 在任务日志界面,点击任务的“执行备注”的“查看”按钮,可以看到匹配子任务以及触发子任务执行的日志信息,如无信息则表示未触发子任务执行,可参考下图。 @@ -1102,7 +1102,8 @@ - 25、底层系统日志级别规范调整,清理遗留代码; - 26、建表SQL优化,支持同步创建制定编码的库和表; - 27、系统安全性优化,登陆Token写Cookie时进行MD5加密,同时Cookie启用HttpOnly; - +- 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。 +- 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环; ### TODO LIST - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限; @@ -1118,6 +1119,7 @@ - 11、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件; - 12、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性; - 13、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发; +- 14、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题; ## 七、其他 diff --git a/doc/db/tables_xxl_job.sql b/doc/db/tables_xxl_job.sql index 6de1918..ed32895 100644 --- a/doc/db/tables_xxl_job.sql +++ b/doc/db/tables_xxl_job.sql @@ -167,7 +167,7 @@ `glue_source` text COMMENT 'GLUE源代码', `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注', `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间', - `child_jobkey` varchar(255) DEFAULT NULL COMMENT '子任务Key', + `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 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 ec1138d..51847ac 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 @@ -31,7 +31,7 @@ private String glueRemark; // GLUE备注 private Date glueUpdatetime; // GLUE更新时间 - private String childJobKey; // 子任务Key + private String childJobId; // 子任务ID,多个逗号分隔 // copy from quartz private String jobStatus; // 任务状态 【base on quartz】 @@ -172,12 +172,12 @@ this.glueUpdatetime = glueUpdatetime; } - public String getChildJobKey() { - return childJobKey; + public String getChildJobId() { + return childJobId; } - public void setChildJobKey(String childJobKey) { - this.childJobKey = childJobKey; + public void setChildJobId(String childJobId) { + this.childJobId = childJobId; } public String getJobStatus() { diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java index 2695569..c9f7f04 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java @@ -4,7 +4,6 @@ import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobLog; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.core.util.MailUtil; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; @@ -125,7 +124,7 @@ " " + " \n" + " 执行器\n" + - " JobKey\n" + + " 任务ID\n" + " 任务描述\n" + " 告警类型\n" + " \n" + @@ -156,7 +155,7 @@ XxlJobGroup group = XxlJobDynamicScheduler.xxlJobGroupDao.load(Integer.valueOf(info.getJobGroup())); String title = "调度中心监控报警"; - String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", JobKeyUtil.formatJobKey(info), info.getJobDesc()); + String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", info.getId(), info.getJobDesc()); MailUtil.sendMail(email, title, content); } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java deleted file mode 100644 index 7eaea1f..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JobKeyUtil.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.xxl.job.admin.core.util; - -import com.xxl.job.admin.core.model.XxlJobInfo; -import org.apache.commons.lang3.StringUtils; - -/** - * job key util - * - * @author xuxueli 2017-12-22 18:48:45 - */ -public class JobKeyUtil { - - /** - * format job key - * - * @param xxlJobInfo - * @return - */ - public static String formatJobKey(XxlJobInfo xxlJobInfo){ - return String.valueOf(xxlJobInfo.getJobGroup()) - .concat("_").concat(String.valueOf(xxlJobInfo.getId())); - } - - /** - * parse jobId from JobKey - * - * @param jobKey - * @return - */ - public static int parseJobId(String jobKey){ - if (jobKey!=null && jobKey.trim().length()>0) { - String[] jobKeyArr = jobKey.split("_"); - if (jobKeyArr.length == 2) { - String jobIdStr = jobKeyArr[1]; - if (StringUtils.isNotBlank(jobIdStr) && StringUtils.isNumeric(jobIdStr)) { - int jobId = Integer.valueOf(jobIdStr); - return jobId; - } - } - } - return -1; - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java index 6f989b8..352b4c9 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java @@ -1,11 +1,7 @@ package com.xxl.job.admin.service.impl; -import com.xxl.job.admin.controller.JobApiController; import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobLog; -import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.trigger.XxlJobTrigger; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobLogDao; import com.xxl.job.admin.dao.XxlJobRegistryDao; @@ -16,7 +12,6 @@ import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; import org.apache.commons.lang3.StringUtils; -import org.quartz.SchedulerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -68,21 +63,21 @@ String callbackMsg = null; if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) { XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId()); - if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobKey())) { + if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobId())) { callbackMsg = "

>>>>>>>>>>>触发子任务<<<<<<<<<<<
"; - String[] childJobKeys = xxlJobInfo.getChildJobKey().split(","); - for (int i = 0; i < childJobKeys.length; i++) { - int childJobId = JobKeyUtil.parseJobId(childJobKeys[i]); + String[] childJobIds = xxlJobInfo.getChildJobId().split(","); + for (int i = 0; i < childJobIds.length; i++) { + int childJobId = (StringUtils.isNotBlank(childJobIds[i]) && StringUtils.isNumeric(childJobIds[i]))?Integer.valueOf(childJobIds[i]):-1; if (childJobId > 0) { ReturnT triggerChildResult = xxlJobService.triggerJob(childJobId); // add msg - callbackMsg += MessageFormat.format("{0}/{1} [JobKey={2}], 触发{3}, 触发备注: {4}
", - (i+1), childJobKeys.length, childJobKeys[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg()); + callbackMsg += MessageFormat.format("{0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4}
", + (i+1), childJobIds.length, childJobIds[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg()); } else { - callbackMsg += MessageFormat.format(" {0}/{1} [JobKey={2}], 触发失败, 触发备注: JobKey格式错误
", - (i+1), childJobKeys.length, childJobKeys[i]); + callbackMsg += MessageFormat.format(" {0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误
", + (i+1), childJobIds.length, childJobIds[i]); } } 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 820e896..eecef34 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 @@ -5,7 +5,6 @@ import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.util.JobKeyUtil; import com.xxl.job.admin.dao.XxlJobGroupDao; import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobLogDao; @@ -104,19 +103,20 @@ jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", "")); } - // childJobKey valid - if (StringUtils.isNotBlank(jobInfo.getChildJobKey())) { - String[] childJobKeys = jobInfo.getChildJobKey().split(","); - for (String childJobKeyItem: childJobKeys) { - int childJobId = JobKeyUtil.parseJobId(childJobKeyItem); - if (childJobId <= 0) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem)); - } - XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(childJobId); - if (childJobInfo==null) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})无效", childJobKeyItem)); + // ChildJobId valid + if (StringUtils.isNotBlank(jobInfo.getChildJobId())) { + String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ","); + for (String childJobIdItem: childJobIds) { + if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) { + XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem)); + if (childJobInfo==null) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem)); + } + } else { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem)); } } + jobInfo.setChildJobId(StringUtils.join(childJobIds, ",")); } // add in db @@ -167,19 +167,24 @@ return new ReturnT(ReturnT.FAIL_CODE, "失败处理策略非法"); } - // childJobKey valid - if (StringUtils.isNotBlank(jobInfo.getChildJobKey())) { - String[] childJobKeys = jobInfo.getChildJobKey().split(","); - for (String childJobKeyItem: childJobKeys) { - int childJobId = JobKeyUtil.parseJobId(childJobKeyItem); - if (childJobId <= 0) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem)); - } - XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(childJobId); - if (childJobInfo==null) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})无效", childJobKeyItem)); + // ChildJobId valid + if (StringUtils.isNotBlank(jobInfo.getChildJobId())) { + String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ","); + for (String childJobIdItem: childJobIds) { + if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) { + XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem)); + if (childJobInfo==null) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem)); + } + // avoid cycle relate + if (childJobInfo.getId() == jobInfo.getId()) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})不可与父任务重复", childJobIdItem)); + } + } else { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem)); } } + jobInfo.setChildJobId(StringUtils.join(childJobIds, ",")); } // stage job info @@ -198,7 +203,7 @@ exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam()); exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy()); exists_jobInfo.setExecutorFailStrategy(jobInfo.getExecutorFailStrategy()); - exists_jobInfo.setChildJobKey(jobInfo.getChildJobKey()); + exists_jobInfo.setChildJobId(jobInfo.getChildJobId()); xxlJobInfoDao.update(exists_jobInfo); // fresh quartz 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 9be9b8e..a5c3abd 100644 --- a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml +++ b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml @@ -27,7 +27,7 @@ - + @@ -48,7 +48,7 @@ t.glue_source, t.glue_remark, t.glue_updatetime, - t.child_jobkey + t.child_jobid