任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环;

This commit is contained in:
xuxueli 2017-12-25 21:48:20 +08:00
parent 5a1834d721
commit 4ce20c1038
14 changed files with 90 additions and 166 deletions

View File

@ -374,7 +374,7 @@ XXL-JOB是一个轻量级分布式任务调度框架其核心设计目标是
GLUE模式(Python):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "python" 脚本;
GLUE模式(NodeJS):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "nodejs" 脚本;
- JobHandler运行模式为 "BEAN模式" 时生效对应执行器中新开发的JobHandler类“@JobHandler”注解自定义的value值
- 子任务Key每个任务都拥有一个唯一的任务Key(任务Key可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务Key所对应的任务的一次主动调度。
- 子任务每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务ID所对应的任务的一次主动调度。
- 阻塞处理策略:调度过于密集执行器来不及处理时的处理策略;
单机串行默认调度请求进入单机执行器后调度请求进入FIFO队列并以串行方式运行
丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败;
@ -699,7 +699,7 @@ xxl-job-admin#com.xxl.job.admin.controller.JobApiController.callback
#### 5.4.9 调度日志
调度中心每次进行任务调度,都会记录一条任务日志,任务日志主要包括以下三部分内容:
- 任务信息包括“执行器地址”、“JobHandler”和“执行参数”等属性点击JobKey可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码;
- 任务信息包括“执行器地址”、“JobHandler”和“执行参数”等属性点击任务ID按钮可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码;
- 调度信息:包括“调度时间”、“调度结果”和“调度日志”等,根据这些参数,可以了解“调度中心”发起调度请求时具体情况。
- 执行信息:包括“执行时间”、“执行结果”和“执行日志”等,根据这些参数,可以了解在“执行器”端任务执行的具体情况;
@ -716,9 +716,9 @@ xxl-job-admin#com.xxl.job.admin.controller.JobApiController.callback
- 执行日志任务执行过程中业务代码中打印的完整执行日志见“4.7 查看执行日志”;
#### 5.4.10 任务依赖
原理XXL-JOB中每个任务都对应有一个任务Key同时每个任务支持设置属性“子任务Key”因此通过“任务Key”可以匹配任务依赖关系。
原理XXL-JOB中每个任务都对应有一个任务ID同时每个任务支持设置属性“子任务ID”因此通过“任务ID”可以匹配任务依赖关系。
当父任务执行结束并且执行成功时,将会根据“子任务Key”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。
当父任务执行结束并且执行成功时,将会根据“子任务ID”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。
在任务日志界面,点击任务的“执行备注”的“查看”按钮,可以看到匹配子任务以及触发子任务执行的日志信息,如无信息则表示未触发子任务执行,可参考下图。
@ -1102,7 +1102,8 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
- 25、底层系统日志级别规范调整清理遗留代码
- 26、建表SQL优化支持同步创建制定编码的库和表
- 27、系统安全性优化登陆Token写Cookie时进行MD5加密同时Cookie启用HttpOnly
- 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。
- 29、任务循环依赖问题修复避免子任务与父任务重复导致的调度死循环
### TODO LIST
- 1、任务权限管理执行器为粒度分配权限核心操作校验权限
@ -1118,6 +1119,7 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
- 11、执行器Log清理功能调度中心Log删除时同步删除执行器中的Log文件
- 12、Bean模式任务JobHandler自动从执行器中查询展示为下拉框选择后自动填充任务名称等属性
- 13、API事件触发类型任务更类似MQ消息支持"动态传参、延时消费"该类型任务不走Quartz单独建立MQ消息表调度中心竞争触发
- 14、任务依赖增强新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题;
## 七、其他

View File

@ -167,7 +167,7 @@ CREATE TABLE `XXL_JOB_QRTZ_TRIGGER_INFO` (
`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;

View File

@ -31,7 +31,7 @@ public class XxlJobInfo {
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 @@ public class XxlJobInfo {
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() {

View File

@ -4,7 +4,6 @@ import com.xxl.job.admin.core.model.XxlJobGroup;
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 @@ public class JobFailMonitorHelper {
" <thead style=\"font-weight: bold;color: #ffffff;background-color: #ff8c00;\" >" +
" <tr>\n" +
" <td>执行器</td>\n" +
" <td>JobKey</td>\n" +
" <td>任务ID</td>\n" +
" <td>任务描述</td>\n" +
" <td>告警类型</td>\n" +
" </tr>\n" +
@ -156,7 +155,7 @@ public class JobFailMonitorHelper {
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);
}

View File

@ -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;
}
}

View File

@ -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.RegistryParam;
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 @@ public class AdminBizImpl implements AdminBiz {
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 = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发子任务<<<<<<<<<<< </span><br>";
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<String> triggerChildResult = xxlJobService.triggerJob(childJobId);
// add msg
callbackMsg += MessageFormat.format("{0}/{1} [JobKey={2}], 触发{3}, 触发备注: {4} <br>",
(i+1), childJobKeys.length, childJobKeys[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg());
callbackMsg += MessageFormat.format("{0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4} <br>",
(i+1), childJobIds.length, childJobIds[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg());
} else {
callbackMsg += MessageFormat.format(" {0}/{1} [JobKey={2}], 触发失败, 触发备注: JobKey格式错误 <br>",
(i+1), childJobKeys.length, childJobKeys[i]);
callbackMsg += MessageFormat.format(" {0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误 <br>",
(i+1), childJobIds.length, childJobIds[i]);
}
}

View File

@ -5,7 +5,6 @@ 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.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 @@ public class XxlJobServiceImpl implements XxlJobService {
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<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem));
}
XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(childJobId);
// 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<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})无效", childJobKeyItem));
return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem));
}
} else {
return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem));
}
}
jobInfo.setChildJobId(StringUtils.join(childJobIds, ","));
}
// add in db
@ -167,19 +167,24 @@ public class XxlJobServiceImpl implements XxlJobService {
return new ReturnT<String>(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<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem));
}
XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(childJobId);
// 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<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})无效", childJobKeyItem));
return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem));
}
// avoid cycle relate
if (childJobInfo.getId() == jobInfo.getId()) {
return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})不可与父任务重复", childJobIdItem));
}
} else {
return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem));
}
}
jobInfo.setChildJobId(StringUtils.join(childJobIds, ","));
}
// stage job info
@ -198,7 +203,7 @@ public class XxlJobServiceImpl implements XxlJobService {
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

View File

@ -27,7 +27,7 @@
<result column="glue_remark" property="glueRemark" />
<result column="glue_updatetime" property="glueUpdatetime" />
<result column="child_jobkey" property="childJobKey" />
<result column="child_jobid" property="childJobId" />
</resultMap>
<sql id="Base_Column_List">
@ -48,7 +48,7 @@
t.glue_source,
t.glue_remark,
t.glue_updatetime,
t.child_jobkey
t.child_jobid
</sql>
<select id="pageList" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
@ -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}
);
<!--<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
SELECT LAST_INSERT_ID()
@ -146,7 +146,7 @@
glue_source = #{glueSource},
glue_remark = #{glueRemark},
glue_updatetime = #{glueUpdatetime},
child_jobkey = #{childJobKey}
child_jobid = #{childJobId}
WHERE id = #{id}
</update>

View File

@ -66,9 +66,8 @@
<table id="job_list" class="table table-bordered table-striped" width="100%" >
<thead>
<tr>
<th name="id" >id</th>
<th name="id" >任务ID</th>
<th name="jobGroup" >jobGroup</th>
<th name="childJobKey" >JobKey</th>
<th name="jobDesc" >描述</th>
<th name="glueType" >运行模式</th>
<th name="executorParam" >任务参数</th>
@ -144,8 +143,8 @@
<div class="form-group">
<label for="firstname" class="col-sm-2 control-label">执行参数<font color="black">*</font></label>
<div class="col-sm-4"><input type="text" class="form-control" name="executorParam" placeholder="请输入执行参数" maxlength="512" ></div>
<label for="lastname" class="col-sm-2 control-label">子任务Key<font color="black">*</font></label>
<div class="col-sm-4"><input type="text" class="form-control" name="childJobKey" placeholder="请输入子任务的任务Key,如存在多个逗号分隔" maxlength="100" ></div>
<label for="lastname" class="col-sm-2 control-label">子任务ID<font color="black">*</font></label>
<div class="col-sm-4"><input type="text" class="form-control" name="childJobId" placeholder="请输入子任务的任务ID,如存在多个逗号分隔" maxlength="100" ></div>
</div>
<div class="form-group">
<label for="firstname" class="col-sm-2 control-label">阻塞处理策略<font color="red">*</font></label>
@ -312,8 +311,8 @@ process.exit(0)
<div class="form-group">
<label for="firstname" class="col-sm-2 control-label">执行参数<font color="black">*</font></label>
<div class="col-sm-4"><input type="text" class="form-control" name="executorParam" placeholder="请输入执行参数" maxlength="512" ></div>
<label for="lastname" class="col-sm-2 control-label">子任务Key<font color="black">*</font></label>
<div class="col-sm-4"><input type="text" class="form-control" name="childJobKey" placeholder="请输入子任务的任务Key,如存在多个逗号分隔" maxlength="100" ></div>
<label for="lastname" class="col-sm-2 control-label">子任务ID<font color="black">*</font></label>
<div class="col-sm-4"><input type="text" class="form-control" name="childJobId" placeholder="请输入子任务的任务ID,如存在多个逗号分隔" maxlength="100" ></div>
</div>
<div class="form-group">
<label for="firstname" class="col-sm-2 control-label">阻塞处理策略<font color="red">*</font></label>

View File

@ -90,10 +90,8 @@
<table id="joblog_list" class="table table-bordered table-striped display" width="100%" >
<thead>
<tr>
<th name="id" >id</th>
<th name="jobGroup" >执行器ID</th>
<th name="jobId" >任务ID</th>
<th name="JobKey" >JobKey</th>
<th name="jobGroup" >执行器ID</th>
<#--<th name="executorAddress" >执行器地址</th>
<th name="glueType" >运行模式</th>
<th name="executorParam" >任务参数</th>-->

View File

@ -20,7 +20,7 @@ $(function() {
"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 @@ $(function() {
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 @@ $(function() {
$('#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);

View File

@ -89,15 +89,10 @@ $(function() {
"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)";
@ -116,27 +111,10 @@ $(function() {
temp += '<br>运行模式' + glueTypeTitle;
temp += '<br>任务参数' + row.executorParam;
return '<a class="logTips" href="javascript:;" >'+ jobKey +'<span style="display:none;">'+ temp +'</span></a>';
return '<a class="logTips" href="javascript:;" >'+ row.jobId +'<span style="display:none;">'+ temp +'</span></a>';
}
},
// { "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 ) {

View File

@ -45,7 +45,7 @@ public class XxlJobInfoDaoTest {
info.setGlueType("setGlueType");
info.setGlueSource("setGlueSource");
info.setGlueRemark("setGlueRemark");
info.setChildJobKey("setChildJobKey");
info.setChildJobId("1");
int count = xxlJobInfoDao.save(info);
@ -63,7 +63,7 @@ public class XxlJobInfoDaoTest {
info2.setGlueSource("setGlueSource2");
info2.setGlueRemark("setGlueRemark2");
info2.setGlueUpdatetime(new Date());
info2.setChildJobKey("setChildJobKey2");
info2.setChildJobId("1");
int item2 = xxlJobInfoDao.update(info2);

View File

@ -20,7 +20,7 @@ public class MailUtilTest {
" <thead style=\"font-weight: bold;color: #ffffff;background-color: #ff8c00;\" >" +
" <tr>\n" +
" <td>执行器</td>\n" +
" <td>JobKey</td>\n" +
" <td>任务ID</td>\n" +
" <td>任务描述</td>\n" +
" <td>告警类型</td>\n" +
" </tr>\n" +
@ -35,9 +35,10 @@ public class MailUtilTest {
" <tbody>\n" +
"</table>";
mailBodyTemplate = MessageFormat.format(mailBodyTemplate, "执行器A", "1_1", "任务A1");
String title = "调度中心监控报警";
String content = MessageFormat.format(mailBodyTemplate, "执行器A", "01", "任务A1");
boolean ret = MailUtil.sendMail("931591021@qq.com", "调度中心监控报警" , mailBodyTemplate);
boolean ret = MailUtil.sendMail("931591021@qq.com", title, content);
System.out.println(ret);
}