失败重试完整支持:任务流程分为调度和执行,之前仅支持调度失败的重试;目前支持执行失败的重试,通过任务返回值判断。

This commit is contained in:
xuxueli 2017-12-20 15:25:47 +08:00
parent 451eb2b7b3
commit f587f10e32
14 changed files with 69 additions and 27 deletions

View File

@ -1065,6 +1065,7 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
- 11、任务Cron长度扩展支持至128位 - 11、任务Cron长度扩展支持至128位
- 12、调度报表优化支持时间区间筛选 - 12、调度报表优化支持时间区间筛选
- 13、Log组件支持输出异常栈信息底层实现优化 - 13、Log组件支持输出异常栈信息底层实现优化
- 14、失败重试完整支持任务流程分为调度和执行之前仅支持调度失败的重试目前支持执行失败的重试通过任务返回值判断。
### TODO LIST ### TODO LIST
- 1、任务权限管理执行器为粒度分配权限核心操作校验权限 - 1、任务权限管理执行器为粒度分配权限核心操作校验权限
@ -1085,7 +1086,7 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
- 16、任务告警邮件优化调整为表格形式 - 16、任务告警邮件优化调整为表格形式
- 17、JobHandler提供 init/destroy 方法,支持自定义任务线程销毁逻辑; - 17、JobHandler提供 init/destroy 方法,支持自定义任务线程销毁逻辑;
- 18、执行器回调地址/日志地址格式兼容,是否已"/"结尾均支持; - 18、执行器回调地址/日志地址格式兼容,是否已"/"结尾均支持;
- 19、失败重试完整支持任务流程分为触发和执行目前仅支持触发失败的重试后续支持任务执行失败的重试通过任务返回值判断。

View File

@ -6,6 +6,7 @@ import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
import com.xxl.job.admin.core.util.MailUtil; import com.xxl.job.admin.core.util.MailUtil;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -51,13 +52,15 @@ public class JobFailMonitorHelper {
if (log == null) { if (log == null) {
continue; continue;
} }
if (ReturnT.SUCCESS_CODE == log.getTriggerCode() && log.getHandleCode() == 0) { if (IJobHandler.SUCCESS.getCode() == log.getTriggerCode() && log.getHandleCode() == 0) {
JobFailMonitorHelper.monitor(jobLogId); JobFailMonitorHelper.monitor(jobLogId);
logger.info(">>>>>>>>>>> job monitor, job running, JobLogId:{}", jobLogId); logger.info(">>>>>>>>>>> job monitor, job running, JobLogId:{}", jobLogId);
} else if (ReturnT.SUCCESS_CODE == log.getTriggerCode() && ReturnT.SUCCESS_CODE == log.getHandleCode()) { } else if (IJobHandler.SUCCESS.getCode() == log.getHandleCode()) {
// job success, pass // job success, pass
logger.info(">>>>>>>>>>> job monitor, job success, JobLogId:{}", jobLogId); logger.info(">>>>>>>>>>> job monitor, job success, JobLogId:{}", jobLogId);
} else if (ReturnT.FAIL_CODE == log.getTriggerCode() || ReturnT.FAIL_CODE == log.getHandleCode()) { } else if (IJobHandler.FAIL.getCode() == log.getTriggerCode()
|| IJobHandler.FAIL.getCode() == log.getHandleCode()
|| IJobHandler.FAIL_RETRY.getCode() == log.getHandleCode() ) {
// job fail, // job fail,
failAlarm(log); failAlarm(log);
logger.info(">>>>>>>>>>> job monitor, job fail, JobLogId:{}", jobLogId); logger.info(">>>>>>>>>>> job monitor, job fail, JobLogId:{}", jobLogId);

View File

@ -171,7 +171,7 @@ public class XxlJobTrigger {
// 4.3trigger (fail retry) // 4.3trigger (fail retry)
if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) { if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) {
triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList); triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList);
triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>失败重试<<<<<<<<<<< </span><br>").append(triggerResult.getMsg()); triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>调度失败重试<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
} }
} }

View File

@ -13,6 +13,7 @@ import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.model.HandleCallbackParam; import com.xxl.job.core.biz.model.HandleCallbackParam;
import com.xxl.job.core.biz.model.RegistryParam; import com.xxl.job.core.biz.model.RegistryParam;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.quartz.SchedulerException; import org.quartz.SchedulerException;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -46,7 +47,7 @@ public class AdminBizImpl implements AdminBiz {
for (HandleCallbackParam handleCallbackParam: callbackParamList) { for (HandleCallbackParam handleCallbackParam: callbackParamList) {
ReturnT<String> callbackResult = callback(handleCallbackParam); ReturnT<String> callbackResult = callback(handleCallbackParam);
logger.info(">>>>>>>>> JobApiController.callback {}, handleCallbackParam={}, callbackResult={}", logger.info(">>>>>>>>> JobApiController.callback {}, handleCallbackParam={}, callbackResult={}",
(callbackResult.getCode()==ReturnT.SUCCESS_CODE?"success":"fail"), handleCallbackParam, callbackResult); (callbackResult.getCode()==IJobHandler.SUCCESS.getCode()?"success":"fail"), handleCallbackParam, callbackResult);
} }
return ReturnT.SUCCESS; return ReturnT.SUCCESS;
@ -58,28 +59,39 @@ public class AdminBizImpl implements AdminBiz {
if (log == null) { if (log == null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "log item not found."); return new ReturnT<String>(ReturnT.FAIL_CODE, "log item not found.");
} }
if (log.getHandleCode() > 0) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "log repeate callback."); // avoid repeat callback, trigger child job etc
}
// trigger success, to trigger child job, and avoid repeat trigger child job // trigger success, to trigger child job
String childTriggerMsg = null; String callbackMsg = null;
if (ReturnT.SUCCESS_CODE==handleCallbackParam.getExecuteResult().getCode() && ReturnT.SUCCESS_CODE!=log.getHandleCode()) { if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) {
XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId()); XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId());
if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobKey())) { if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobKey())) {
childTriggerMsg = "<hr>"; callbackMsg = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发子任务<<<<<<<<<<< </span><br>";
String[] childJobKeys = xxlJobInfo.getChildJobKey().split(","); String[] childJobKeys = xxlJobInfo.getChildJobKey().split(",");
for (int i = 0; i < childJobKeys.length; i++) { for (int i = 0; i < childJobKeys.length; i++) {
String[] jobKeyArr = childJobKeys[i].split("_"); String[] jobKeyArr = childJobKeys[i].split("_");
if (jobKeyArr!=null && jobKeyArr.length==2) { if (jobKeyArr!=null && jobKeyArr.length==2) {
ReturnT<String> triggerChildResult = xxlJobService.triggerJob(Integer.valueOf(jobKeyArr[1])); ReturnT<String> triggerChildResult = xxlJobService.triggerJob(Integer.valueOf(jobKeyArr[1]));
// add msg // add msg
childTriggerMsg += MessageFormat.format("<br> {0}/{1} 触发子任务{2}, 子任务Key: {3}, 子任务触发备注: {4}", callbackMsg += MessageFormat.format("{0}/{1} [JobKey={2}], 触发{3}, 触发备注: {4} <br>",
(i+1), childJobKeys.length, (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), childJobKeys[i], triggerChildResult.getMsg()); (i+1), childJobKeys.length, childJobKeys[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg());
} else { } else {
childTriggerMsg += MessageFormat.format("<br> {0}/{1} 触发子任务失败, 子任务Key格式错误, 子任务Key: {2}", callbackMsg += MessageFormat.format(" {0}/{1} [JobKey={2}], 触发失败, 触发备注: JobKey格式错误 <br>",
(i+1), childJobKeys.length, childJobKeys[i]); (i+1), childJobKeys.length, childJobKeys[i]);
} }
} }
} }
} else if (IJobHandler.FAIL_RETRY.getCode() == handleCallbackParam.getExecuteResult().getCode()){
ReturnT<String> retryTriggerResult = xxlJobService.triggerJob(log.getJobId());
callbackMsg = "<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>执行失败重试<<<<<<<<<<< </span><br>";
callbackMsg += MessageFormat.format("触发{0}, 触发备注: {1}",
(retryTriggerResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), retryTriggerResult.getMsg());
} }
// handle msg // handle msg
@ -90,8 +102,8 @@ public class AdminBizImpl implements AdminBiz {
if (handleCallbackParam.getExecuteResult().getMsg() != null) { if (handleCallbackParam.getExecuteResult().getMsg() != null) {
handleMsg.append(handleCallbackParam.getExecuteResult().getMsg()); handleMsg.append(handleCallbackParam.getExecuteResult().getMsg());
} }
if (childTriggerMsg !=null) { if (callbackMsg != null) {
handleMsg.append("<br>子任务触发备注:").append(childTriggerMsg); handleMsg.append(callbackMsg);
} }
// success, save log // success, save log

View File

@ -146,9 +146,16 @@ $(function() {
{ {
"data": 'triggerCode', "data": 'triggerCode',
"render": function ( data, type, row ) { "render": function ( data, type, row ) {
return (data==200)?'<span style="color: green">成功</span>':(data==500)?'<span style="color: red">失败</span>':(data==0)?'':data; var html = data;
if (data == 200) {
html = '<span style="color: green">成功</span>';
} else if (data == 500) {
html = '<span style="color: red">失败</span>';
} else if (data == 0) {
html = '';
}
return html;
} }
}, },
{ {
"data": 'triggerMsg', "data": 'triggerMsg',
@ -165,7 +172,17 @@ $(function() {
{ {
"data": 'handleCode', "data": 'handleCode',
"render": function ( data, type, row ) { "render": function ( data, type, row ) {
return (data==200)?'<span style="color: green">成功</span>':(data==500)?'<span style="color: red">失败</span>':(data==0)?'':data; var html = data;
if (data == 200) {
html = '<span style="color: green">成功</span>';
} else if (data == 500) {
html = '<span style="color: red">失败</span>';
} else if (data == 501) {
html = '<span style="color: red">失败重试</span>';
} else if (data == 0) {
html = '';
}
return html;
} }
}, },
{ {

View File

@ -3,11 +3,20 @@ package com.xxl.job.core.handler;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
/** /**
* remote job handler * job handler
*
* @author xuxueli 2015-12-19 19:06:38 * @author xuxueli 2015-12-19 19:06:38
*/ */
public abstract class IJobHandler { public abstract class IJobHandler {
/** success */
public static final ReturnT<String> SUCCESS = new ReturnT<String>(200, null);
/** fail */
public static final ReturnT<String> FAIL = new ReturnT<String>(500, null);
/** fail retry */
public static final ReturnT<String> FAIL_RETRY = new ReturnT<String>(501, null);
/** /**
* job handler * job handler
* @param params * @param params

View File

@ -54,7 +54,7 @@ public class ScriptJobHandler extends IJobHandler {
// invoke // invoke
XxlJobLogger.log("----------- script file:"+ scriptFileName +" -----------"); XxlJobLogger.log("----------- script file:"+ scriptFileName +" -----------");
int exitValue = ScriptUtil.execToFile(cmd, scriptFileName, logFileName, params); int exitValue = ScriptUtil.execToFile(cmd, scriptFileName, logFileName, params);
ReturnT<String> result = (exitValue==0)?ReturnT.SUCCESS:new ReturnT<String>(ReturnT.FAIL_CODE, "script exit value("+exitValue+") is failed"); ReturnT<String> result = (exitValue==0)?IJobHandler.SUCCESS:new ReturnT<String>(IJobHandler.FAIL.getCode(), "script exit value("+exitValue+") is failed");
return result; return result;
} }

View File

@ -120,7 +120,7 @@ public class JobThread extends Thread{
XxlJobLogger.log("<br>----------- xxl-job job execute start -----------<br>----------- Params:" + Arrays.toString(handlerParams)); XxlJobLogger.log("<br>----------- xxl-job job execute start -----------<br>----------- Params:" + Arrays.toString(handlerParams));
executeResult = handler.execute(handlerParams); executeResult = handler.execute(handlerParams);
if (executeResult == null) { if (executeResult == null) {
executeResult = ReturnT.FAIL; executeResult = IJobHandler.FAIL;
} }
XxlJobLogger.log("<br>----------- xxl-job job execute end(finish) -----------<br>----------- ReturnT:" + executeResult); XxlJobLogger.log("<br>----------- xxl-job job execute end(finish) -----------<br>----------- ReturnT:" + executeResult);

View File

@ -27,7 +27,7 @@ public class DemoJobHandler extends IJobHandler {
XxlJobLogger.log("beat at:" + i); XxlJobLogger.log("beat at:" + i);
TimeUnit.SECONDS.sleep(2); TimeUnit.SECONDS.sleep(2);
} }
return ReturnT.SUCCESS; return SUCCESS;
} }
} }

View File

@ -29,7 +29,7 @@ public class ShardingJobHandler extends IJobHandler {
} }
} }
return ReturnT.SUCCESS; return SUCCESS;
} }
} }

View File

@ -32,7 +32,7 @@ public class DemoJobHandler extends IJobHandler {
XxlJobLogger.log("beat at:" + i); XxlJobLogger.log("beat at:" + i);
TimeUnit.SECONDS.sleep(2); TimeUnit.SECONDS.sleep(2);
} }
return ReturnT.SUCCESS; return SUCCESS;
} }
} }

View File

@ -33,7 +33,7 @@ public class ShardingJobHandler extends IJobHandler {
} }
} }
return ReturnT.SUCCESS; return SUCCESS;
} }
} }

View File

@ -32,7 +32,7 @@ public class DemoJobHandler extends IJobHandler {
XxlJobLogger.log("beat at:" + i); XxlJobLogger.log("beat at:" + i);
TimeUnit.SECONDS.sleep(2); TimeUnit.SECONDS.sleep(2);
} }
return ReturnT.SUCCESS; return SUCCESS;
} }
} }

View File

@ -33,7 +33,7 @@ public class ShardingJobHandler extends IJobHandler {
} }
} }
return ReturnT.SUCCESS; return SUCCESS;
} }
} }