- 3、【新增】新增任务辅助工具 "XxlJobHelper",提供统一任务辅助能力,包括:任务上下文信息维护获取(任务参数、任务ID、分片参数)、日志输出、任务结果设置……等;

- 3.1、"ShardingUtil" 组件废弃:改用 "XxlJobHelper.getShardIndex()/getShardTotal();" 获取分片参数;
    - 3.2、"XxlJobLogger" 组件废弃:改用 "XxlJobHelper.log" 进行日志输出;
- 4、【优化】任务核心类 "IJobHandler" 的 "execute" 方法取消出入参设计。改为通过 "XxlJobHelper.getJobParam" 获取任务参数并替代方法入参,通过 "XxlJobHelper.handleSuccess/handleFail" 设置任务结果并替代方法出参;
This commit is contained in:
xueli.xue 2020-11-05 20:07:32 +08:00
parent 6339f528c5
commit 5dfc6a1092
44 changed files with 968 additions and 1042 deletions

View File

@ -397,9 +397,8 @@ Source code is organized by maven,unzip it and structure is as follows:
xxl-job-adminschedule admin center
xxl-job-corepublic common dependent library
xxl-job-executorexecutor Sample(Select appropriate version of executor,Can be used directly,You can also refer to it and transform existing projects into executors
       xxl-job-executor-sample-springSpring versionexecutors managed by Springgeneral and recommend;
xxl-job-executor-sample-springSpring versionexecutors managed by Springgeneral and recommend;
xxl-job-executor-sample-springbootSpringboot versionexecutors managed by Springboot;
xxl-job-executor-sample-jfinalJFinal versionexecutors managed by JFinal;
### 2.3 Configure and delploy "Schedule Center"

View File

@ -559,7 +559,6 @@ XXL-JOB是一个分布式任务调度平台其核心设计目标是开发迅
xxl-job-executor-sample-springbootSpringboot版本通过Springboot管理执行器推荐这种方式
xxl-job-executor-sample-springSpring版本通过Spring容器管理执行器比较通用
xxl-job-executor-sample-frameless无框架版本
xxl-job-executor-sample-jfinalJFinal版本通过JFinal管理执行器
### 2.3 配置部署“调度中心”
@ -714,7 +713,6 @@ public XxlJobSpringExecutor xxlJobExecutor() {
xxl-job-executor-sample-springboot项目编译打包成springboot类型的可执行JAR包命令启动即可
xxl-job-executor-sample-spring项目编译打包成WAR包并部署到tomcat中。
xxl-job-executor-sample-jfinal同上
至此“执行器”项目已经部署结束。
@ -1239,7 +1237,7 @@ xxl-job-admin#com.xxl.job.admin.controller.JobApiController.callback
“执行器”接收到“调度中心”的调度请求时如果任务类型为“Bean模式”将会匹配Spring容器中的“Bean模式任务”然后调用其execute方法执行任务逻辑。如果任务类型为“GLUE模式”将会加载GLue代码实例化Java对象注入依赖的Spring服务注意Glue代码中注入的Spring服务必须存在与该“执行器”项目的Spring容器中然后调用execute方法执行任务逻辑。
#### 5.5.5 任务日志
XXL-JOB会为每次调度请求生成一个单独的日志文件需要通过 "XxlJobLogger.log" 打印执行日志,“调度中心”查看执行日志时将会加载对应的日志文件。
XXL-JOB会为每次调度请求生成一个单独的日志文件需要通过 "XxlJobHelper.log" 打印执行日志,“调度中心”查看执行日志时将会加载对应的日志文件。
(历史版本通过重写LOG4J的Appender实现存在依赖限制该方式在新版本已经被抛弃)
@ -2062,37 +2060,38 @@ data: post-data
注意XxlJobSpringExecutor组件个别字段调整“appName” 调整为 “appname” ,升级时该组件时需要注意;
### 7.31 版本 v2.3.0 Release Notes[迭代中]
- 1、新增调度过期策略调度中心错过调度时间的补偿处理策略包括忽略、立即补偿触发一次等
- 2、新增触发策略除了常规Cron、API、父子任务触发方式外新增提供 "固定间隔触发、固定延时触发(规划)" 两种新触发方式;
- 3、Cron编辑器增强Cron编辑器修改cron时可实时查看最近运行时间;
- 4、Cron编辑器问题修复修复小概率情况下cron单个字段修改时导致其他字段被重置问题
- 5、新增任务属性 "XxlJobContext" 统一维护任务上下文信息包括任务ID、分片参数等方便运行时存取任务相关信息
- 6.1、废弃 "ShardingUtil" 组件:改用 "XxlJobContext.getXxlJobContext().getShardIndex()/getShardTotal();" 获取分片参数;
- 6.2、日志组件逻辑调整:日志组件改为通过 XxlJobContext 获取任务上下文并匹配写入对应日志文件;
- 6、执行器注册组件优化注册逻辑调整为异步方式提高注册性能
- 7、执行器鉴权校验执行器启动时主动校验accessToken为空则主动Warn告警已规划安全强化AccessToken动态生成、动态启停等
- 8、邮箱告警配置优化将"spring.mail.from"与"spring.mail.username"属性拆分开,更加灵活的支持一些无密码邮箱服务;
- 9、多个项目依赖升级至较新稳定版本如netty、groovy、spring、springboot、mybatis等
- 10、UI组件常规升级提升组件稳定性
- 11、调度中心页面交互优化用户管理模块密码列取消多处表达autocomplete取消执行器管理模块XSS拦截校验等
- 12、通用HTTP任务HandlerhttpJobHandler优化修复 "setDoOutput(true)" 导致任务请求GetMethod失效问题
- 13、执行器Commandhandler示例任务优化修复极端情况下脚本进程挂起问题
- 14、调度通讯组件优化修复RestFul方式调用 DotNet 版本执行器时心跳检测失败问题;
- 15、调度中心远程执行日志查询乱码问题修复
- 16、调度中心组件加载顺序优化修复极端情况下调度组件初始慢导致的调度失败问题
- 17、执行器注册线程优化修复极端情况下初始化失败时导致NPE问题
- 18、调度线程连接池优化修复连接有效性校验超时问题
- 19、执行器注册表字段优化解决执行器注册节点过多导致注册信息存储和更新失败的问题
- 20、轮训路由策略优化修复小概率下并发问题
- 21、页面redirect跳转后https变为http问题修复
- 22、执行器日志清理优化修复小概率下日志文件为空导致清理异常问题
- 23、执行器示例项目规范整理
- 24、任务调度生命周期重构调度schedule、触发(trigger)、执行handle、回调(callback)、结束complete
- 25、[规划中]任务日志重构:一次调度只记录一条主任务,维护起止时间和状态。
- 1、【新增】调度过期策略调度中心错过调度时间的补偿处理策略包括忽略、立即补偿触发一次等
- 2、【新增】触发策略除了常规Cron、API、父子任务触发方式外新增提供 "固定间隔触发、(固定延时触发,实验中)" 新触发方式;
- 3、【新增】新增任务辅助工具 "XxlJobHelper"提供统一任务辅助能力包括任务上下文信息维护获取任务参数、任务ID、分片参数、日志输出、任务结果设置……等
- 3.1、"ShardingUtil" 组件废弃:改用 "XxlJobHelper.getShardIndex()/getShardTotal();" 获取分片参数;
- 3.2、"XxlJobLogger" 组件废弃:改用 "XxlJobHelper.log" 进行日志输出;
- 4、【优化】任务核心类 "IJobHandler" 的 "execute" 方法取消出入参设计。改为通过 "XxlJobHelper.getJobParam" 获取任务参数并替代方法入参,通过 "XxlJobHelper.handleSuccess/handleFail" 设置任务结果并替代方法出参;
- 4、【优化】Cron编辑器增强Cron编辑器修改cron时可实时查看最近运行时间;
- 5、【优化】执行器示例项目规范整理
- 6、【优化】任务调度生命周期重构调度schedule、触发(trigger)、执行handle、回调(callback)、结束complete
- 7、【优化】[规划中]任务日志重构:一次调度只记录一条主任务,维护起止时间和状态。
- 普通任务:只记录一条主任务;
- 广播任务:记录一条主任务,每个分片任务记录一条次任务,关联在主任务上;
- 重试任务:失败时,新增主任务。所有调度记录,包括入口调度和重试调度,均挂载主任务上。
- 26、[规划中]分片任务:全部完成后才会出发后置节点;
- 8、【优化】[规划中]分片任务:全部完成后才会出发后置节点;
- 9、【优化】执行器注册组件优化注册逻辑调整为异步方式提高注册性能
- 10、【优化】执行器鉴权校验执行器启动时主动校验accessToken为空则主动Warn告警已规划安全强化AccessToken动态生成、动态启停等
- 11、【优化】邮箱告警配置优化将"spring.mail.from"与"spring.mail.username"属性拆分开,更加灵活的支持一些无密码邮箱服务;
- 12、【优化】多个项目依赖升级至较新稳定版本如netty、groovy、spring、springboot、mybatis等
- 13、【优化】UI组件常规升级提升组件稳定性
- 14、【优化】调度中心页面交互优化用户管理模块密码列取消多处表达autocomplete取消执行器管理模块XSS拦截校验等
- 15、【修复】Cron编辑器问题修复修复小概率情况下cron单个字段修改时导致其他字段被重置问题
- 16、【修复】通用HTTP任务HandlerhttpJobHandler优化修复 "setDoOutput(true)" 导致任务请求GetMethod失效问题
- 17、【修复】执行器Commandhandler示例任务优化修复极端情况下脚本进程挂起问题
- 18、【修复】调度通讯组件优化修复RestFul方式调用 DotNet 版本执行器时心跳检测失败问题;
- 19、【修复】调度中心远程执行日志查询乱码问题修复
- 20、【修复】调度中心组件加载顺序优化修复极端情况下调度组件初始慢导致的调度失败问题
- 21、【修复】执行器注册线程优化修复极端情况下初始化失败时导致NPE问题
- 22、【修复】调度线程连接池优化修复连接有效性校验超时问题
- 23、【修复】执行器注册表字段优化解决执行器注册节点过多导致注册信息存储和更新失败的问题
- 24、【修复】轮训路由策略优化修复小概率下并发问题
- 25、【修复】页面redirect跳转后https变为http问题修复
- 26、【修复】执行器日志清理优化修复小概率下日志文件为空导致清理异常问题
### 7.32 版本 v2.4.0 Release Notes[规划中]

View File

@ -7,7 +7,7 @@ import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.context.XxlJobContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -47,7 +47,7 @@ public class XxlJobCompleter {
// 1handle success, to trigger child job
String triggerChildMsg = null;
if (IJobHandler.SUCCESS.getCode() == xxlJobLog.getHandleCode()) {
if (XxlJobContext.HANDLE_COCE_SUCCESS == xxlJobLog.getHandleCode()) {
XxlJobInfo xxlJobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(xxlJobLog.getJobId());
if (xxlJobInfo!=null && xxlJobInfo.getChildJobId()!=null && xxlJobInfo.getChildJobId().trim().length()>0) {
triggerChildMsg = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_child_run") +"<<<<<<<<<<< </span><br>";

View File

@ -1,12 +1,11 @@
package com.xxl.job.admin.core.thread;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.complete.XxlJobCompleter;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.model.HandleCallbackParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.util.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -144,7 +143,7 @@ public class JobCompleteHelper {
for (HandleCallbackParam handleCallbackParam: callbackParamList) {
ReturnT<String> callbackResult = callback(handleCallbackParam);
logger.debug(">>>>>>>>> JobApiController.callback {}, handleCallbackParam={}, callbackResult={}",
(callbackResult.getCode()== IJobHandler.SUCCESS.getCode()?"success":"fail"), handleCallbackParam, callbackResult);
(callbackResult.getCode()== ReturnT.SUCCESS_CODE?"success":"fail"), handleCallbackParam, callbackResult);
}
}
});
@ -167,13 +166,13 @@ public class JobCompleteHelper {
if (log.getHandleMsg()!=null) {
handleMsg.append(log.getHandleMsg()).append("<br>");
}
if (handleCallbackParam.getExecuteResult().getMsg() != null) {
handleMsg.append(handleCallbackParam.getExecuteResult().getMsg());
if (handleCallbackParam.getHandleMsg() != null) {
handleMsg.append(handleCallbackParam.getHandleMsg());
}
// success, save log
log.setHandleTime(new Date());
log.setHandleCode(handleCallbackParam.getExecuteResult().getCode());
log.setHandleCode(handleCallbackParam.getHandleCode());
log.setHandleMsg(handleMsg.toString());
XxlJobCompleter.updateHandleInfoAndFinish(log);

View File

@ -374,6 +374,12 @@ $(function() {
$("#addModal .form input[name='schedule_conf_CRON']").show().siblings().remove();
$("#addModal .form input[name='schedule_conf_CRON']").cronGen({});
// init scheduleType
$("#updateModal .form select[name=scheduleType]").change();
// init glueType
$("#updateModal .form select[name=glueType]").change();
$('#addModal').modal({backdrop: false, keyboard: false}).modal('show');
});
var addModalValidate = $("#addModal .form").validate({

View File

@ -245,16 +245,14 @@
<textarea class="glueSource_java" style="display:none;" >
package com.xxl.job.service.handler;
import com.xxl.job.core.log.XxlJobLogger;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.IJobHandler;
public class DemoGlueJobHandler extends IJobHandler {
@Override
public ReturnT<String> execute(String param) throws Exception {
XxlJobLogger.log("XXL-JOB, Hello World.");
return ReturnT.SUCCESS;
public void execute() throws Exception {
XxlJobHelper.log("XXL-JOB, Hello World.");
}
}

View File

@ -5,6 +5,7 @@ import com.xxl.job.core.biz.client.AdminBizClient;
import com.xxl.job.core.biz.model.HandleCallbackParam;
import com.xxl.job.core.biz.model.RegistryParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobContext;
import com.xxl.job.core.enums.RegistryConfig;
import org.junit.Assert;
import org.junit.Test;
@ -30,7 +31,7 @@ public class AdminBizTest {
HandleCallbackParam param = new HandleCallbackParam();
param.setLogId(1);
param.setExecuteResult(ReturnT.SUCCESS);
param.setHandleCode(XxlJobContext.HANDLE_COCE_SUCCESS);
List<HandleCallbackParam> callbackParamList = Arrays.asList(param);

View File

@ -11,13 +11,15 @@ public class HandleCallbackParam implements Serializable {
private long logId;
private long logDateTim;
private ReturnT<String> executeResult;
private int handleCode;
private String handleMsg;
public HandleCallbackParam(){}
public HandleCallbackParam(long logId, long logDateTim, ReturnT<String> executeResult) {
public HandleCallbackParam(long logId, long logDateTim, int handleCode, String handleMsg) {
this.logId = logId;
this.logDateTim = logDateTim;
this.executeResult = executeResult;
this.handleCode = handleCode;
this.handleMsg = handleMsg;
}
public long getLogId() {
@ -36,12 +38,20 @@ public class HandleCallbackParam implements Serializable {
this.logDateTim = logDateTim;
}
public ReturnT<String> getExecuteResult() {
return executeResult;
public int getHandleCode() {
return handleCode;
}
public void setExecuteResult(ReturnT<String> executeResult) {
this.executeResult = executeResult;
public void setHandleCode(int handleCode) {
this.handleCode = handleCode;
}
public String getHandleMsg() {
return handleMsg;
}
public void setHandleMsg(String handleMsg) {
this.handleMsg = handleMsg;
}
@Override
@ -49,7 +59,8 @@ public class HandleCallbackParam implements Serializable {
return "HandleCallbackParam{" +
"logId=" + logId +
", logDateTim=" + logDateTim +
", executeResult=" + executeResult +
", handleCode=" + handleCode +
", handleMsg='" + handleMsg + '\'' +
'}';
}

View File

@ -8,16 +8,31 @@ package com.xxl.job.core.context;
*/
public class XxlJobContext {
public static final int HANDLE_COCE_SUCCESS = 200;
public static final int HANDLE_COCE_FAIL = 500;
public static final int HANDLE_COCE_TIMEOUT = 502;
// ---------------------- base info ----------------------
/**
* job id
*/
private final long jobId;
/**
* job param
*/
private final String jobParam;
// ---------------------- for log ----------------------
/**
* job log filename
*/
private final String jobLogFileName;
// ---------------------- for shard ----------------------
/**
* shard index
*/
@ -28,18 +43,42 @@ public class XxlJobContext {
*/
private final int shardTotal;
// ---------------------- for handle ----------------------
public XxlJobContext(long jobId, String jobLogFileName, int shardIndex, int shardTotal) {
/**
* handleCodeThe result status of job execution
*
* 200 : success
* 500 : fail
* 502 : timeout
*
*/
private int handleCode;
/**
* handleMsgThe simple log msg of job execution
*/
private String handleMsg;
public XxlJobContext(long jobId, String jobParam, String jobLogFileName, int shardIndex, int shardTotal) {
this.jobId = jobId;
this.jobParam = jobParam;
this.jobLogFileName = jobLogFileName;
this.shardIndex = shardIndex;
this.shardTotal = shardTotal;
this.handleCode = HANDLE_COCE_SUCCESS; // default success
}
public long getJobId() {
return jobId;
}
public String getJobParam() {
return jobParam;
}
public String getJobLogFileName() {
return jobLogFileName;
}
@ -52,6 +91,21 @@ public class XxlJobContext {
return shardTotal;
}
public void setHandleCode(int handleCode) {
this.handleCode = handleCode;
}
public int getHandleCode() {
return handleCode;
}
public void setHandleMsg(String handleMsg) {
this.handleMsg = handleMsg;
}
public String getHandleMsg() {
return handleMsg;
}
// ---------------------- tool ----------------------

View File

@ -0,0 +1,255 @@
package com.xxl.job.core.context;
import com.xxl.job.core.log.XxlJobFileAppender;
import com.xxl.job.core.util.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
/**
* helper for xxl-job
*
* @author xuxueli 2020-11-05
*/
public class XxlJobHelper {
// ---------------------- base info ----------------------
/**
* current JobId
*
* @return
*/
public static long getJobId() {
XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
if (xxlJobContext == null) {
return -1;
}
return xxlJobContext.getJobId();
}
/**
* current JobParam
*
* @return
*/
public static String getJobParam() {
XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
if (xxlJobContext == null) {
return null;
}
return xxlJobContext.getJobParam();
}
// ---------------------- for log ----------------------
/**
* current JobLogFileName
*
* @return
*/
public static String getJobLogFileName() {
XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
if (xxlJobContext == null) {
return null;
}
return xxlJobContext.getJobLogFileName();
}
// ---------------------- for shard ----------------------
/**
* current ShardIndex
*
* @return
*/
public static int getShardIndex() {
XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
if (xxlJobContext == null) {
return -1;
}
return xxlJobContext.getShardIndex();
}
/**
* current ShardTotal
*
* @return
*/
public static int getShardTotal() {
XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
if (xxlJobContext == null) {
return -1;
}
return xxlJobContext.getShardTotal();
}
// ---------------------- tool for log ----------------------
private static Logger logger = LoggerFactory.getLogger("xxl-job logger");
/**
* append log with pattern
*
* @param appendLogPattern like "aaa {} bbb {} ccc"
* @param appendLogArguments like "111, true"
*/
public static boolean log(String appendLogPattern, Object ... appendLogArguments) {
FormattingTuple ft = MessageFormatter.arrayFormat(appendLogPattern, appendLogArguments);
String appendLog = ft.getMessage();
/*appendLog = appendLogPattern;
if (appendLogArguments!=null && appendLogArguments.length>0) {
appendLog = MessageFormat.format(appendLogPattern, appendLogArguments);
}*/
StackTraceElement callInfo = new Throwable().getStackTrace()[1];
return logDetail(callInfo, appendLog);
}
/**
* append exception stack
*
* @param e
*/
public static boolean log(Throwable e) {
StringWriter stringWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stringWriter));
String appendLog = stringWriter.toString();
StackTraceElement callInfo = new Throwable().getStackTrace()[1];
return logDetail(callInfo, appendLog);
}
/**
* append log
*
* @param callInfo
* @param appendLog
*/
private static boolean logDetail(StackTraceElement callInfo, String appendLog) {
XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
if (xxlJobContext == null) {
return false;
}
/*// "yyyy-MM-dd HH:mm:ss [ClassName]-[MethodName]-[LineNumber]-[ThreadName] log";
StackTraceElement[] stackTraceElements = new Throwable().getStackTrace();
StackTraceElement callInfo = stackTraceElements[1];*/
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(DateUtil.formatDateTime(new Date())).append(" ")
.append("["+ callInfo.getClassName() + "#" + callInfo.getMethodName() +"]").append("-")
.append("["+ callInfo.getLineNumber() +"]").append("-")
.append("["+ Thread.currentThread().getName() +"]").append(" ")
.append(appendLog!=null?appendLog:"");
String formatAppendLog = stringBuffer.toString();
// appendlog
String logFileName = xxlJobContext.getJobLogFileName();
if (logFileName!=null && logFileName.trim().length()>0) {
XxlJobFileAppender.appendLog(logFileName, formatAppendLog);
return true;
} else {
logger.info(">>>>>>>>>>> {}", formatAppendLog);
return false;
}
}
// ---------------------- tool for handleResult ----------------------
/**
* handle success
*
* @return
*/
public static boolean handleSuccess(){
return handleResult(XxlJobContext.HANDLE_COCE_SUCCESS, null);
}
/**
* handle success with log msg
*
* @param handleMsg
* @return
*/
public static boolean handleSuccess(String handleMsg) {
return handleResult(XxlJobContext.HANDLE_COCE_SUCCESS, handleMsg);
}
/**
* handle fail
*
* @return
*/
public static boolean handleFail(){
return handleResult(XxlJobContext.HANDLE_COCE_FAIL, null);
}
/**
* handle fail with log msg
*
* @param handleMsg
* @return
*/
public static boolean handleFail(String handleMsg) {
return handleResult(XxlJobContext.HANDLE_COCE_FAIL, handleMsg);
}
/**
* handle timeout
*
* @return
*/
public static boolean handleTimeout(){
return handleResult(XxlJobContext.HANDLE_COCE_TIMEOUT, null);
}
/**
* handle timeout with log msg
*
* @param handleMsg
* @return
*/
public static boolean handleTimeout(String handleMsg){
return handleResult(XxlJobContext.HANDLE_COCE_TIMEOUT, handleMsg);
}
/**
* @param handleCode
*
* 200 : success
* 500 : fail
* 502 : timeout
*
* @param handleMsg
* @return
*/
public static boolean handleResult(int handleCode, String handleMsg) {
XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
if (xxlJobContext == null) {
return false;
}
xxlJobContext.setHandleCode(handleCode);
if (handleMsg != null) {
xxlJobContext.setHandleMsg(handleMsg);
}
return true;
}
}

View File

@ -169,13 +169,13 @@ public class XxlJobExecutor {
// ---------------------- job handler repository ----------------------
private static ConcurrentMap<String, IJobHandler> jobHandlerRepository = new ConcurrentHashMap<String, IJobHandler>();
public static IJobHandler loadJobHandler(String name){
return jobHandlerRepository.get(name);
}
public static IJobHandler registJobHandler(String name, IJobHandler jobHandler){
logger.info(">>>>>>>>>>> xxl-job register jobhandler success, name:{}, jobHandler:{}", name, jobHandler);
return jobHandlerRepository.put(name, jobHandler);
}
public static IJobHandler loadJobHandler(String name){
return jobHandlerRepository.get(name);
}
// ---------------------- job thread repository ----------------------

View File

@ -0,0 +1,122 @@
package com.xxl.job.core.executor.impl;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.handler.impl.MethodJobHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* xxl-job executor (for frameless)
*
* @author xuxueli 2020-11-05
*/
public class XxlJobSimpleExecutor extends XxlJobExecutor {
private static final Logger logger = LoggerFactory.getLogger(XxlJobSimpleExecutor.class);
private List<Object> xxlJobBeanList = new ArrayList<>();
public List<Object> getXxlJobBeanList() {
return xxlJobBeanList;
}
public void setXxlJobBeanList(List<Object> xxlJobBeanList) {
this.xxlJobBeanList = xxlJobBeanList;
}
public void start() {
// init JobHandler Repository (for method)
initJobHandlerMethodRepository(xxlJobBeanList);
// super start
try {
super.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void destroy() {
super.destroy();
}
private void initJobHandlerMethodRepository(List<Object> xxlJobBeanList) {
if (xxlJobBeanList==null || xxlJobBeanList.size()==0) {
return;
}
// init job handler from method
for (Object bean: xxlJobBeanList) {
// method
Method[] methods = bean.getClass().getDeclaredMethods();
if (methods==null || methods.length==0) {
continue;
}
for (Method executeMethod : methods) {
// anno
XxlJob xxlJob = executeMethod.getAnnotation(XxlJob.class);
if (xxlJob == null) {
continue;
}
String name = xxlJob.value();
if (name.trim().length() == 0) {
throw new RuntimeException("xxl-job method-jobhandler name invalid, for[" + bean.getClass() + "#" + executeMethod.getName() + "] .");
}
if (loadJobHandler(name) != null) {
throw new RuntimeException("xxl-job jobhandler[" + name + "] naming conflicts.");
}
// execute method
/*if (!(method.getParameterTypes().length == 1 && method.getParameterTypes()[0].isAssignableFrom(String.class))) {
throw new RuntimeException("xxl-job method-jobhandler param-classtype invalid, for[" + bean.getClass() + "#" + method.getName() + "] , " +
"The correct method format like \" public ReturnT<String> execute(String param) \" .");
}
if (!method.getReturnType().isAssignableFrom(ReturnT.class)) {
throw new RuntimeException("xxl-job method-jobhandler return-classtype invalid, for[" + bean.getClass() + "#" + method.getName() + "] , " +
"The correct method format like \" public ReturnT<String> execute(String param) \" .");
}*/
executeMethod.setAccessible(true);
// init and destory
Method initMethod = null;
Method destroyMethod = null;
if (xxlJob.init().trim().length() > 0) {
try {
initMethod = bean.getClass().getDeclaredMethod(xxlJob.init());
initMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new RuntimeException("xxl-job method-jobhandler initMethod invalid, for[" + bean.getClass() + "#" + executeMethod.getName() + "] .");
}
}
if (xxlJob.destroy().trim().length() > 0) {
try {
destroyMethod = bean.getClass().getDeclaredMethod(xxlJob.destroy());
destroyMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new RuntimeException("xxl-job method-jobhandler destroyMethod invalid, for[" + bean.getClass() + "#" + executeMethod.getName() + "] .");
}
}
// registry jobhandler
registJobHandler(name, new MethodJobHandler(bean, executeMethod, initMethod, destroyMethod));
}
}
}
}

View File

@ -1,6 +1,5 @@
package com.xxl.job.core.executor.impl;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.glue.GlueFactory;
import com.xxl.job.core.handler.annotation.XxlJob;
@ -104,7 +103,7 @@ public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationC
}
for (Map.Entry<Method, XxlJob> methodXxlJobEntry : annotatedMethods.entrySet()) {
Method method = methodXxlJobEntry.getKey();
Method executeMethod = methodXxlJobEntry.getKey();
XxlJob xxlJob = methodXxlJobEntry.getValue();
if (xxlJob == null) {
continue;
@ -112,22 +111,23 @@ public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationC
String name = xxlJob.value();
if (name.trim().length() == 0) {
throw new RuntimeException("xxl-job method-jobhandler name invalid, for[" + bean.getClass() + "#" + method.getName() + "] .");
throw new RuntimeException("xxl-job method-jobhandler name invalid, for[" + bean.getClass() + "#" + executeMethod.getName() + "] .");
}
if (loadJobHandler(name) != null) {
throw new RuntimeException("xxl-job jobhandler[" + name + "] naming conflicts.");
}
// execute method
if (!(method.getParameterTypes().length == 1 && method.getParameterTypes()[0].isAssignableFrom(String.class))) {
/*if (!(method.getParameterTypes().length == 1 && method.getParameterTypes()[0].isAssignableFrom(String.class))) {
throw new RuntimeException("xxl-job method-jobhandler param-classtype invalid, for[" + bean.getClass() + "#" + method.getName() + "] , " +
"The correct method format like \" public ReturnT<String> execute(String param) \" .");
}
if (!method.getReturnType().isAssignableFrom(ReturnT.class)) {
throw new RuntimeException("xxl-job method-jobhandler return-classtype invalid, for[" + bean.getClass() + "#" + method.getName() + "] , " +
"The correct method format like \" public ReturnT<String> execute(String param) \" .");
}
method.setAccessible(true);
}*/
executeMethod.setAccessible(true);
// init and destory
Method initMethod = null;
@ -138,7 +138,7 @@ public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationC
initMethod = bean.getClass().getDeclaredMethod(xxlJob.init());
initMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new RuntimeException("xxl-job method-jobhandler initMethod invalid, for[" + bean.getClass() + "#" + method.getName() + "] .");
throw new RuntimeException("xxl-job method-jobhandler initMethod invalid, for[" + bean.getClass() + "#" + executeMethod.getName() + "] .");
}
}
if (xxlJob.destroy().trim().length() > 0) {
@ -146,12 +146,12 @@ public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationC
destroyMethod = bean.getClass().getDeclaredMethod(xxlJob.destroy());
destroyMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new RuntimeException("xxl-job method-jobhandler destroyMethod invalid, for[" + bean.getClass() + "#" + method.getName() + "] .");
throw new RuntimeException("xxl-job method-jobhandler destroyMethod invalid, for[" + bean.getClass() + "#" + executeMethod.getName() + "] .");
}
}
// registry jobhandler
registJobHandler(name, new MethodJobHandler(bean, method, initMethod, destroyMethod));
registJobHandler(name, new MethodJobHandler(bean, executeMethod, initMethod, destroyMethod));
}
}

View File

@ -1,9 +1,5 @@
package com.xxl.job.core.handler;
import com.xxl.job.core.biz.model.ReturnT;
import java.lang.reflect.InvocationTargetException;
/**
* job handler
*
@ -12,28 +8,21 @@ import java.lang.reflect.InvocationTargetException;
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 timeout */
public static final ReturnT<String> FAIL_TIMEOUT = new ReturnT<String>(502, null);
/**
* execute handler, invoked when executor receives a scheduling request
*
* @param param
* @return
* @throws Exception
*/
public abstract ReturnT<String> execute(String param) throws Exception;
public abstract void execute() throws Exception;
/*@Deprecated
public abstract ReturnT<String> execute(String param) throws Exception;*/
/**
* init handler, invoked when JobThread init
*/
public void init() throws InvocationTargetException, IllegalAccessException {
public void init() throws Exception {
// do something
}
@ -41,7 +30,7 @@ public abstract class IJobHandler {
/**
* destroy handler, invoked when JobThread destroy
*/
public void destroy() throws InvocationTargetException, IllegalAccessException {
public void destroy() throws Exception {
// do something
}

View File

@ -1,8 +1,7 @@
package com.xxl.job.core.handler.impl;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobLogger;
/**
* glue job handler
@ -22,9 +21,9 @@ public class GlueJobHandler extends IJobHandler {
}
@Override
public ReturnT<String> execute(String param) throws Exception {
XxlJobLogger.log("----------- glue.version:"+ glueUpdatetime +" -----------");
return jobHandler.execute(param);
public void execute() throws Exception {
XxlJobHelper.log("----------- glue.version:"+ glueUpdatetime +" -----------");
jobHandler.execute();
}
}

View File

@ -1,9 +1,7 @@
package com.xxl.job.core.handler.impl;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
@ -25,19 +23,19 @@ public class MethodJobHandler extends IJobHandler {
}
@Override
public ReturnT<String> execute(String param) throws Exception {
return (ReturnT<String>) method.invoke(target, new Object[]{param});
public void execute() throws Exception {
method.invoke(target);
}
@Override
public void init() throws InvocationTargetException, IllegalAccessException {
public void init() throws Exception {
if(initMethod != null) {
initMethod.invoke(target);
}
}
@Override
public void destroy() throws InvocationTargetException, IllegalAccessException {
public void destroy() throws Exception {
if(destroyMethod != null) {
destroyMethod.invoke(target);
}

View File

@ -1,11 +1,10 @@
package com.xxl.job.core.handler.impl;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobContext;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.glue.GlueTypeEnum;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobFileAppender;
import com.xxl.job.core.log.XxlJobLogger;
import com.xxl.job.core.util.ScriptUtil;
import java.io.File;
@ -46,10 +45,11 @@ public class ScriptJobHandler extends IJobHandler {
}
@Override
public ReturnT<String> execute(String param) throws Exception {
public void execute() throws Exception {
if (!glueType.isScript()) {
return new ReturnT<String>(IJobHandler.FAIL.getCode(), "glueType["+ glueType +"] invalid.");
XxlJobHelper.handleFail("glueType["+ glueType +"] invalid.");
return;
}
// cmd
@ -72,18 +72,20 @@ public class ScriptJobHandler extends IJobHandler {
// script params0=param1=分片序号2=分片总数
String[] scriptParams = new String[3];
scriptParams[0] = param;
scriptParams[0] = XxlJobHelper.getJobParam();
scriptParams[1] = String.valueOf(XxlJobContext.getXxlJobContext().getShardIndex());
scriptParams[2] = String.valueOf(XxlJobContext.getXxlJobContext().getShardTotal());
// invoke
XxlJobLogger.log("----------- script file:"+ scriptFileName +" -----------");
XxlJobHelper.log("----------- script file:"+ scriptFileName +" -----------");
int exitValue = ScriptUtil.execToFile(cmd, scriptFileName, logFileName, scriptParams);
if (exitValue == 0) {
return IJobHandler.SUCCESS;
XxlJobHelper.handleSuccess();
return;
} else {
return new ReturnT<String>(IJobHandler.FAIL.getCode(), "script exit value("+exitValue+") is failed");
XxlJobHelper.handleFail("script exit value("+exitValue+") is failed");
return ;
}
}

View File

@ -1,86 +0,0 @@
package com.xxl.job.core.log;
import com.xxl.job.core.context.XxlJobContext;
import com.xxl.job.core.util.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
/**
* Created by xuxueli on 17/4/28.
*/
public class XxlJobLogger {
private static Logger logger = LoggerFactory.getLogger("xxl-job logger");
/**
* append log
*
* @param callInfo
* @param appendLog
*/
private static void logDetail(StackTraceElement callInfo, String appendLog) {
/*// "yyyy-MM-dd HH:mm:ss [ClassName]-[MethodName]-[LineNumber]-[ThreadName] log";
StackTraceElement[] stackTraceElements = new Throwable().getStackTrace();
StackTraceElement callInfo = stackTraceElements[1];*/
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(DateUtil.formatDateTime(new Date())).append(" ")
.append("["+ callInfo.getClassName() + "#" + callInfo.getMethodName() +"]").append("-")
.append("["+ callInfo.getLineNumber() +"]").append("-")
.append("["+ Thread.currentThread().getName() +"]").append(" ")
.append(appendLog!=null?appendLog:"");
String formatAppendLog = stringBuffer.toString();
// appendlog
String logFileName = XxlJobContext.getXxlJobContext().getJobLogFileName();
if (logFileName!=null && logFileName.trim().length()>0) {
XxlJobFileAppender.appendLog(logFileName, formatAppendLog);
} else {
logger.info(">>>>>>>>>>> {}", formatAppendLog);
}
}
/**
* append log with pattern
*
* @param appendLogPattern like "aaa {} bbb {} ccc"
* @param appendLogArguments like "111, true"
*/
public static void log(String appendLogPattern, Object ... appendLogArguments) {
FormattingTuple ft = MessageFormatter.arrayFormat(appendLogPattern, appendLogArguments);
String appendLog = ft.getMessage();
/*appendLog = appendLogPattern;
if (appendLogArguments!=null && appendLogArguments.length>0) {
appendLog = MessageFormat.format(appendLogPattern, appendLogArguments);
}*/
StackTraceElement callInfo = new Throwable().getStackTrace()[1];
logDetail(callInfo, appendLog);
}
/**
* append exception stack
*
* @param e
*/
public static void log(Throwable e) {
StringWriter stringWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stringWriter));
String appendLog = stringWriter.toString();
StackTraceElement callInfo = new Throwable().getStackTrace()[1];
logDetail(callInfo, appendLog);
}
}

View File

@ -4,10 +4,10 @@ import com.xxl.job.core.biz.model.HandleCallbackParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import com.xxl.job.core.context.XxlJobContext;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobFileAppender;
import com.xxl.job.core.log.XxlJobLogger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -106,7 +106,6 @@ public class JobThread extends Thread{
idleTimes++;
TriggerParam triggerParam = null;
ReturnT<String> executeResult = null;
try {
// to check toStop signal, we need cycle, so wo cannot use queue.take(), instand of poll(timeout)
triggerParam = triggerQueue.poll(3L, TimeUnit.SECONDS);
@ -117,54 +116,68 @@ public class JobThread extends Thread{
// log filename, like "logPath/yyyy-MM-dd/9999.log"
String logFileName = XxlJobFileAppender.makeLogFileName(new Date(triggerParam.getLogDateTime()), triggerParam.getLogId());
XxlJobContext.setXxlJobContext(new XxlJobContext(
XxlJobContext xxlJobContext = new XxlJobContext(
triggerParam.getJobId(),
triggerParam.getExecutorParams(),
logFileName,
triggerParam.getBroadcastIndex(),
triggerParam.getBroadcastTotal()));
triggerParam.getBroadcastTotal());
// init job context
XxlJobContext.setXxlJobContext(xxlJobContext);
// execute
XxlJobLogger.log("<br>----------- xxl-job job execute start -----------<br>----------- Param:" + triggerParam.getExecutorParams());
XxlJobHelper.log("<br>----------- xxl-job job execute start -----------<br>----------- Param:" + xxlJobContext.getJobParam());
if (triggerParam.getExecutorTimeout() > 0) {
// limit timeout
Thread futureThread = null;
try {
final TriggerParam triggerParamTmp = triggerParam;
FutureTask<ReturnT<String>> futureTask = new FutureTask<ReturnT<String>>(new Callable<ReturnT<String>>() {
FutureTask<Boolean> futureTask = new FutureTask<Boolean>(new Callable<Boolean>() {
@Override
public ReturnT<String> call() throws Exception {
return handler.execute(triggerParamTmp.getExecutorParams());
public Boolean call() throws Exception {
// init job context
XxlJobContext.setXxlJobContext(xxlJobContext);
handler.execute();
return true;
}
});
futureThread = new Thread(futureTask);
futureThread.start();
executeResult = futureTask.get(triggerParam.getExecutorTimeout(), TimeUnit.SECONDS);
Boolean tempResult = futureTask.get(triggerParam.getExecutorTimeout(), TimeUnit.SECONDS);
} catch (TimeoutException e) {
XxlJobLogger.log("<br>----------- xxl-job job execute timeout");
XxlJobLogger.log(e);
XxlJobHelper.log("<br>----------- xxl-job job execute timeout");
XxlJobHelper.log(e);
executeResult = new ReturnT<String>(IJobHandler.FAIL_TIMEOUT.getCode(), "job execute timeout ");
// handle result
XxlJobHelper.handleTimeout("job execute timeout ");
} finally {
futureThread.interrupt();
}
} else {
// just execute
executeResult = handler.execute(triggerParam.getExecutorParams());
handler.execute();
}
if (executeResult == null) {
executeResult = IJobHandler.FAIL;
// valid execute handle data
if (XxlJobContext.getXxlJobContext().getHandleCode() <= 0) {
XxlJobHelper.handleFail("job handle result lost.");
} else {
executeResult.setMsg(
(executeResult!=null&&executeResult.getMsg()!=null&&executeResult.getMsg().length()>50000)
?executeResult.getMsg().substring(0, 50000).concat("...")
:executeResult.getMsg());
executeResult.setContent(null); // limit obj size
String tempHandleMsg = XxlJobContext.getXxlJobContext().getHandleMsg();
tempHandleMsg = (tempHandleMsg!=null&&tempHandleMsg.length()>50000)
?tempHandleMsg.substring(0, 50000).concat("...")
:tempHandleMsg;
XxlJobContext.getXxlJobContext().setHandleMsg(tempHandleMsg);
}
XxlJobLogger.log("<br>----------- xxl-job job execute end(finish) -----------<br>----------- ReturnT:" + executeResult);
XxlJobHelper.log("<br>----------- xxl-job job execute end(finish) -----------<br>----------- Result: handleCode="
+ XxlJobContext.getXxlJobContext().getHandleCode()
+ ", handleMsg = "
+ XxlJobContext.getXxlJobContext().getHandleMsg()
);
} else {
if (idleTimes > 30) {
@ -175,25 +188,36 @@ public class JobThread extends Thread{
}
} catch (Throwable e) {
if (toStop) {
XxlJobLogger.log("<br>----------- JobThread toStop, stopReason:" + stopReason);
XxlJobHelper.log("<br>----------- JobThread toStop, stopReason:" + stopReason);
}
// handle result
StringWriter stringWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stringWriter));
String errorMsg = stringWriter.toString();
executeResult = new ReturnT<String>(ReturnT.FAIL_CODE, errorMsg);
XxlJobLogger.log("<br>----------- JobThread Exception:" + errorMsg + "<br>----------- xxl-job job execute end(error) -----------");
XxlJobHelper.handleFail(errorMsg);
XxlJobHelper.log("<br>----------- JobThread Exception:" + errorMsg + "<br>----------- xxl-job job execute end(error) -----------");
} finally {
if(triggerParam != null) {
// callback handler info
if (!toStop) {
// commonm
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), triggerParam.getLogDateTime(), executeResult));
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(
triggerParam.getLogId(),
triggerParam.getLogDateTime(),
XxlJobContext.getXxlJobContext().getHandleCode(),
XxlJobContext.getXxlJobContext().getHandleMsg() )
);
} else {
// is killed
ReturnT<String> stopResult = new ReturnT<String>(ReturnT.FAIL_CODE, stopReason + " [job running, killed]");
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), triggerParam.getLogDateTime(), stopResult));
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(
triggerParam.getLogId(),
triggerParam.getLogDateTime(),
XxlJobContext.HANDLE_COCE_FAIL,
stopReason + " [job running, killed]" )
);
}
}
}
@ -204,8 +228,12 @@ public class JobThread extends Thread{
TriggerParam triggerParam = triggerQueue.poll();
if (triggerParam!=null) {
// is killed
ReturnT<String> stopResult = new ReturnT<String>(ReturnT.FAIL_CODE, stopReason + " [job not executed, in the job queue, killed.]");
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), triggerParam.getLogDateTime(), stopResult));
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(
triggerParam.getLogId(),
triggerParam.getLogDateTime(),
XxlJobContext.HANDLE_COCE_FAIL,
stopReason + " [job not executed, in the job queue, killed.]")
);
}
}

View File

@ -4,10 +4,10 @@ import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.model.HandleCallbackParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobContext;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.enums.RegistryConfig;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.log.XxlJobFileAppender;
import com.xxl.job.core.log.XxlJobLogger;
import com.xxl.job.core.util.FileUtil;
import com.xxl.job.core.util.JdkSerializeTool;
import org.slf4j.Logger;
@ -190,10 +190,11 @@ public class TriggerCallbackThread {
String logFileName = XxlJobFileAppender.makeLogFileName(new Date(callbackParam.getLogDateTim()), callbackParam.getLogId());
XxlJobContext.setXxlJobContext(new XxlJobContext(
-1,
null,
logFileName,
-1,
-1));
XxlJobLogger.log(logContent);
XxlJobHelper.log(logContent);
}
}

View File

@ -1,6 +1,6 @@
package com.xxl.job.core.util;
import com.xxl.job.core.log.XxlJobLogger;
import com.xxl.job.core.context.XxlJobHelper;
import java.io.FileOutputStream;
import java.io.IOException;
@ -83,7 +83,7 @@ public class ScriptUtil {
try {
copy(process.getInputStream(), finalFileOutputStream, new byte[1024]);
} catch (IOException e) {
XxlJobLogger.log(e);
XxlJobHelper.log(e);
}
}
});
@ -93,7 +93,7 @@ public class ScriptUtil {
try {
copy(process.getErrorStream(), finalFileOutputStream, new byte[1024]);
} catch (IOException e) {
XxlJobLogger.log(e);
XxlJobHelper.log(e);
}
}
});
@ -109,14 +109,14 @@ public class ScriptUtil {
return exitValue;
} catch (Exception e) {
XxlJobLogger.log(e);
XxlJobHelper.log(e);
return -1;
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
XxlJobLogger.log(e);
XxlJobHelper.log(e);
}
}

View File

@ -14,7 +14,6 @@
<module>xxl-job-executor-sample-frameless</module>
<module>xxl-job-executor-sample-springboot</module>
<module>xxl-job-executor-sample-spring</module>
<module>xxl-job-executor-sample-jfinal</module>
</modules>
</project>

View File

@ -1,54 +0,0 @@
package com.xuxueli.executor.sample.frameless.jobhandler;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobLogger;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
/**
* 命令行任务
*
* @author xuxueli 2018-09-16 03:48:34
*/
public class CommandJobHandler extends IJobHandler {
@Override
public ReturnT<String> execute(String param) throws Exception {
String command = param;
int exitValue = -1;
BufferedReader bufferedReader = null;
try {
// command process
Process process = Runtime.getRuntime().exec(command);
BufferedInputStream bufferedInputStream = new BufferedInputStream(process.getInputStream());
bufferedReader = new BufferedReader(new InputStreamReader(bufferedInputStream));
// command log
String line;
while ((line = bufferedReader.readLine()) != null) {
XxlJobLogger.log(line);
}
// command exit
process.waitFor();
exitValue = process.exitValue();
} catch (Exception e) {
XxlJobLogger.log(e);
} finally {
if (bufferedReader != null) {
bufferedReader.close();
}
}
if (exitValue == 0) {
return IJobHandler.SUCCESS;
} else {
return new ReturnT<String>(IJobHandler.FAIL.getCode(), "command exit value("+exitValue+") is failed");
}
}
}

View File

@ -1,32 +0,0 @@
package com.xuxueli.executor.sample.frameless.jobhandler;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobLogger;
import java.util.concurrent.TimeUnit;
/**
* 任务Handler示例Bean模式
*
* 开发步骤
* 1继承"IJobHandler"com.xxl.job.core.handler.IJobHandler
* 2注册到执行器工厂 "JFinalCoreConfig.initXxlJobExecutor" 中手动注册注解key值对应的是调度中心新建任务的JobHandler属性的值
* 3执行日志需要通过 "XxlJobLogger.log" 打印执行日志
*
* @author xuxueli 2015-12-19 19:43:36
*/
public class DemoJobHandler extends IJobHandler {
@Override
public ReturnT<String> execute(String param) throws Exception {
XxlJobLogger.log("XXL-JOB, Hello World.");
for (int i = 0; i < 5; i++) {
XxlJobLogger.log("beat at:" + i);
TimeUnit.SECONDS.sleep(2);
}
return SUCCESS;
}
}

View File

@ -1,121 +0,0 @@
package com.xuxueli.executor.sample.frameless.jobhandler;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobLogger;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
/**
* 跨平台Http任务
*
* @author xuxueli 2018-09-16 03:48:34
*/
public class HttpJobHandler extends IJobHandler {
@Override
public ReturnT<String> execute(String param) throws Exception {
// param parse
if (param==null || param.trim().length()==0) {
XxlJobLogger.log("param["+ param +"] invalid.");
return ReturnT.FAIL;
}
String[] httpParams = param.split("\n");
String url = null;
String method = null;
String data = null;
for (String httpParam: httpParams) {
if (httpParam.startsWith("url:")) {
url = httpParam.substring(httpParam.indexOf("url:") + 4).trim();
}
if (httpParam.startsWith("method:")) {
method = httpParam.substring(httpParam.indexOf("method:") + 7).trim().toUpperCase();
}
if (httpParam.startsWith("data:")) {
data = httpParam.substring(httpParam.indexOf("data:") + 5).trim();
}
}
// param valid
if (url==null || url.trim().length()==0) {
XxlJobLogger.log("url["+ url +"] invalid.");
return ReturnT.FAIL;
}
if (method==null || !Arrays.asList("GET", "POST").contains(method)) {
XxlJobLogger.log("method["+ method +"] invalid.");
return ReturnT.FAIL;
}
boolean isPostMethod = method.equals("POST");
// request
HttpURLConnection connection = null;
BufferedReader bufferedReader = null;
try {
// connection
URL realUrl = new URL(url);
connection = (HttpURLConnection) realUrl.openConnection();
// connection setting
connection.setRequestMethod(method);
connection.setDoOutput(isPostMethod);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setReadTimeout(5 * 1000);
connection.setConnectTimeout(3 * 1000);
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
connection.setRequestProperty("Accept-Charset", "application/json;charset=UTF-8");
// do connection
connection.connect();
// data
if (isPostMethod && data!=null && data.trim().length()>0) {
DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream());
dataOutputStream.write(data.getBytes("UTF-8"));
dataOutputStream.flush();
dataOutputStream.close();
}
// valid StatusCode
int statusCode = connection.getResponseCode();
if (statusCode != 200) {
throw new RuntimeException("Http Request StatusCode(" + statusCode + ") Invalid.");
}
// result
bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
StringBuilder result = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
result.append(line);
}
String responseMsg = result.toString();
XxlJobLogger.log(responseMsg);
return ReturnT.SUCCESS;
} catch (Exception e) {
XxlJobLogger.log(e);
return ReturnT.FAIL;
} finally {
try {
if (bufferedReader != null) {
bufferedReader.close();
}
if (connection != null) {
connection.disconnect();
}
} catch (Exception e2) {
XxlJobLogger.log(e2);
}
}
}
}

View File

@ -1,36 +0,0 @@
package com.xuxueli.executor.sample.frameless.jobhandler;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobContext;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobLogger;
/**
* 分片广播任务
*
* @author xuxueli 2017-07-25 20:56:50
*/
public class ShardingJobHandler extends IJobHandler {
@Override
public ReturnT<String> execute(String param) throws Exception {
// 分片参数
int shardIndex = XxlJobContext.getXxlJobContext().getShardIndex();
int shardTotal = XxlJobContext.getXxlJobContext().getShardTotal();
XxlJobLogger.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);
// 业务逻辑
for (int i = 0; i < shardTotal; i++) {
if (i == shardIndex) {
XxlJobLogger.log("第 {} 片, 命中分片开始处理", i);
} else {
XxlJobLogger.log("第 {} 片, 忽略", i);
}
}
return SUCCESS;
}
}

View File

@ -1,6 +1,6 @@
package com.xuxueli.executor.sample.frameless;
package com.xxl.job.executor.sample.frameless;
import com.xuxueli.executor.sample.frameless.config.FrameLessXxlJobConfig;
import com.xxl.job.executor.sample.frameless.config.FrameLessXxlJobConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -1,15 +1,13 @@
package com.xuxueli.executor.sample.frameless.config;
package com.xxl.job.executor.sample.frameless.config;
import com.xuxueli.executor.sample.frameless.jobhandler.CommandJobHandler;
import com.xuxueli.executor.sample.frameless.jobhandler.DemoJobHandler;
import com.xuxueli.executor.sample.frameless.jobhandler.HttpJobHandler;
import com.xuxueli.executor.sample.frameless.jobhandler.ShardingJobHandler;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.executor.sample.frameless.jobhandler.SampleXxlJob;
import com.xxl.job.core.executor.impl.XxlJobSimpleExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Properties;
/**
@ -25,25 +23,18 @@ public class FrameLessXxlJobConfig {
}
private XxlJobExecutor xxlJobExecutor = null;
private XxlJobSimpleExecutor xxlJobExecutor = null;
/**
* init
*/
public void initXxlJobExecutor() {
// registry jobhandler
XxlJobExecutor.registJobHandler("demoJobHandler", new DemoJobHandler());
XxlJobExecutor.registJobHandler("shardingJobHandler", new ShardingJobHandler());
XxlJobExecutor.registJobHandler("httpJobHandler", new HttpJobHandler());
XxlJobExecutor.registJobHandler("commandJobHandler", new CommandJobHandler());
// load executor prop
Properties xxlJobProp = loadProperties("xxl-job-executor.properties");
// init executor
xxlJobExecutor = new XxlJobExecutor();
xxlJobExecutor = new XxlJobSimpleExecutor();
xxlJobExecutor.setAdminAddresses(xxlJobProp.getProperty("xxl.job.admin.addresses"));
xxlJobExecutor.setAccessToken(xxlJobProp.getProperty("xxl.job.accessToken"));
xxlJobExecutor.setAppname(xxlJobProp.getProperty("xxl.job.executor.appname"));
@ -53,6 +44,9 @@ public class FrameLessXxlJobConfig {
xxlJobExecutor.setLogPath(xxlJobProp.getProperty("xxl.job.executor.logpath"));
xxlJobExecutor.setLogRetentionDays(Integer.valueOf(xxlJobProp.getProperty("xxl.job.executor.logretentiondays")));
// registry job bean
xxlJobExecutor.setXxlJobBeanList(Arrays.asList(new SampleXxlJob()));
// start executor
try {
xxlJobExecutor.start();

View File

@ -0,0 +1,251 @@
package com.xxl.job.executor.sample.frameless.jobhandler;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
/**
* XxlJob开发示例Bean模式
*
* 开发步骤
* 1任务开发在Spring Bean实例中开发Job方法
* 2注解配置为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")"注解value值对应的是调度中心新建任务的JobHandler属性的值
* 3执行日志需要通过 "XxlJobHelper.log" 打印执行日志
* 4任务结果默认任务结果为 "成功" 状态不需要主动设置如有诉求比如设置任务结果为失败可以通过 "XxlJobHelper.handleFail/handleSuccess" 自主设置任务结果
*
* @author xuxueli 2019-12-11 21:52:51
*/
public class SampleXxlJob {
private static Logger logger = LoggerFactory.getLogger(SampleXxlJob.class);
/**
* 1简单任务示例Bean模式
*/
@XxlJob("demoJobHandler")
public void demoJobHandler() throws Exception {
XxlJobHelper.log("XXL-JOB, Hello World.");
for (int i = 0; i < 5; i++) {
XxlJobHelper.log("beat at:" + i);
TimeUnit.SECONDS.sleep(2);
}
// default success
}
/**
* 2分片广播任务
*/
@XxlJob("shardingJobHandler")
public void shardingJobHandler() throws Exception {
// 分片参数
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
XxlJobHelper.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);
// 业务逻辑
for (int i = 0; i < shardTotal; i++) {
if (i == shardIndex) {
XxlJobHelper.log("第 {} 片, 命中分片开始处理", i);
} else {
XxlJobHelper.log("第 {} 片, 忽略", i);
}
}
}
/**
* 3命令行任务
*/
@XxlJob("commandJobHandler")
public void commandJobHandler() throws Exception {
String command = XxlJobHelper.getJobParam();
int exitValue = -1;
BufferedReader bufferedReader = null;
try {
// command process
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command(command);
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
//Process process = Runtime.getRuntime().exec(command);
BufferedInputStream bufferedInputStream = new BufferedInputStream(process.getInputStream());
bufferedReader = new BufferedReader(new InputStreamReader(bufferedInputStream));
// command log
String line;
while ((line = bufferedReader.readLine()) != null) {
XxlJobHelper.log(line);
}
// command exit
process.waitFor();
exitValue = process.exitValue();
} catch (Exception e) {
XxlJobHelper.log(e);
} finally {
if (bufferedReader != null) {
bufferedReader.close();
}
}
if (exitValue == 0) {
// default success
} else {
XxlJobHelper.handleFail("command exit value("+exitValue+") is failed");
}
}
/**
* 4跨平台Http任务
* 参数示例
* "url: http://www.baidu.com\n" +
* "method: get\n" +
* "data: content\n";
*/
@XxlJob("httpJobHandler")
public void httpJobHandler() throws Exception {
// param parse
String param = XxlJobHelper.getJobParam();
if (param==null || param.trim().length()==0) {
XxlJobHelper.log("param["+ param +"] invalid.");
XxlJobHelper.handleFail();
return;
}
String[] httpParams = param.split("\n");
String url = null;
String method = null;
String data = null;
for (String httpParam: httpParams) {
if (httpParam.startsWith("url:")) {
url = httpParam.substring(httpParam.indexOf("url:") + 4).trim();
}
if (httpParam.startsWith("method:")) {
method = httpParam.substring(httpParam.indexOf("method:") + 7).trim().toUpperCase();
}
if (httpParam.startsWith("data:")) {
data = httpParam.substring(httpParam.indexOf("data:") + 5).trim();
}
}
// param valid
if (url==null || url.trim().length()==0) {
XxlJobHelper.log("url["+ url +"] invalid.");
XxlJobHelper.handleFail();
return;
}
if (method==null || !Arrays.asList("GET", "POST").contains(method)) {
XxlJobHelper.log("method["+ method +"] invalid.");
XxlJobHelper.handleFail();
return;
}
boolean isPostMethod = method.equals("POST");
// request
HttpURLConnection connection = null;
BufferedReader bufferedReader = null;
try {
// connection
URL realUrl = new URL(url);
connection = (HttpURLConnection) realUrl.openConnection();
// connection setting
connection.setRequestMethod(method);
connection.setDoOutput(isPostMethod);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setReadTimeout(5 * 1000);
connection.setConnectTimeout(3 * 1000);
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
connection.setRequestProperty("Accept-Charset", "application/json;charset=UTF-8");
// do connection
connection.connect();
// data
if (isPostMethod && data!=null && data.trim().length()>0) {
DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream());
dataOutputStream.write(data.getBytes("UTF-8"));
dataOutputStream.flush();
dataOutputStream.close();
}
// valid StatusCode
int statusCode = connection.getResponseCode();
if (statusCode != 200) {
throw new RuntimeException("Http Request StatusCode(" + statusCode + ") Invalid.");
}
// result
bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
StringBuilder result = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
result.append(line);
}
String responseMsg = result.toString();
XxlJobHelper.log(responseMsg);
return;
} catch (Exception e) {
XxlJobHelper.log(e);
XxlJobHelper.handleFail();
return;
} finally {
try {
if (bufferedReader != null) {
bufferedReader.close();
}
if (connection != null) {
connection.disconnect();
}
} catch (Exception e2) {
XxlJobHelper.log(e2);
}
}
}
/**
* 5生命周期任务示例任务初始化与销毁时支持自定义相关逻辑
*/
@XxlJob(value = "demoJobHandler2", init = "init", destroy = "destroy")
public void demoJobHandler2() throws Exception {
XxlJobHelper.log("XXL-JOB, Hello World.");
}
public void init(){
logger.info("init");
}
public void destroy(){
logger.info("destory");
}
}

View File

@ -10,7 +10,7 @@ xxl.job.executor.appname=xxl-job-executor-sample
xxl.job.executor.address=
### xxl-job executor server-info
xxl.job.executor.ip=
xxl.job.executor.port=9999
xxl.job.executor.port=9998
### xxl-job executor log-path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### xxl-job executor log-retention-days

View File

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-executor-samples</artifactId>
<version>2.3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>xxl-job-executor-sample-jfinal</artifactId>
<packaging>war</packaging>
<dependencies>
<!-- jfinal -->
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>jfinal-undertow</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>jfinal</artifactId>
<version>4.9.02</version>
</dependency>
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j-api.version}</version>
</dependency>
<!-- xxl-job -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -1,12 +0,0 @@
package com.xuxueli.executor.sample.jfinal;
import com.jfinal.server.undertow.UndertowServer;
import com.xuxueli.executor.sample.jfinal.config.JFinalCoreConfig;
public class XxlJobExecutorApplication {
public static void main(String[] args) {
UndertowServer.start(JFinalCoreConfig.class, 8082, true);
}
}

View File

@ -1,85 +0,0 @@
package com.xuxueli.executor.sample.jfinal.config;
import com.jfinal.config.*;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.template.Engine;
import com.xuxueli.executor.sample.jfinal.controller.IndexController;
import com.xuxueli.executor.sample.jfinal.jobhandler.CommandJobHandler;
import com.xuxueli.executor.sample.jfinal.jobhandler.DemoJobHandler;
import com.xuxueli.executor.sample.jfinal.jobhandler.HttpJobHandler;
import com.xuxueli.executor.sample.jfinal.jobhandler.ShardingJobHandler;
import com.xxl.job.core.executor.XxlJobExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author xuxueli 2017-08-11 14:17:41
*/
public class JFinalCoreConfig extends JFinalConfig {
private Logger logger = LoggerFactory.getLogger(JFinalCoreConfig.class);
// ---------------------- xxl-job executor ----------------------
private XxlJobExecutor xxlJobExecutor = null;
private void initXxlJobExecutor() {
// registry jobhandler
XxlJobExecutor.registJobHandler("demoJobHandler", new DemoJobHandler());
XxlJobExecutor.registJobHandler("shardingJobHandler", new ShardingJobHandler());
XxlJobExecutor.registJobHandler("httpJobHandler", new HttpJobHandler());
XxlJobExecutor.registJobHandler("commandJobHandler", new CommandJobHandler());
// load executor prop
Prop xxlJobProp = PropKit.use("xxl-job-executor.properties");
// init executor
xxlJobExecutor = new XxlJobExecutor();
xxlJobExecutor.setAdminAddresses(xxlJobProp.get("xxl.job.admin.addresses"));
xxlJobExecutor.setAccessToken(xxlJobProp.get("xxl.job.accessToken"));
xxlJobExecutor.setAddress(xxlJobProp.get("xxl.job.executor.address"));
xxlJobExecutor.setAppname(xxlJobProp.get("xxl.job.executor.appname"));
xxlJobExecutor.setIp(xxlJobProp.get("xxl.job.executor.ip"));
xxlJobExecutor.setPort(xxlJobProp.getInt("xxl.job.executor.port"));
xxlJobExecutor.setLogPath(xxlJobProp.get("xxl.job.executor.logpath"));
xxlJobExecutor.setLogRetentionDays(xxlJobProp.getInt("xxl.job.executor.logretentiondays"));
// start executor
try {
xxlJobExecutor.start();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
private void destoryXxlJobExecutor() {
if (xxlJobExecutor != null) {
xxlJobExecutor.destroy();
}
}
// ---------------------- jfinal ----------------------
@Override
public void onStart() {
initXxlJobExecutor();
}
@Override
public void onStop() {
destoryXxlJobExecutor();
}
public void configConstant(Constants me) {
me.setDevMode(true);
}
public void configRoute(Routes routes) {
routes.add("/", IndexController.class);
}
public void configEngine(Engine me) {}
public void configPlugin(Plugins me) {}
public void configInterceptor(Interceptors me) {}
public void configHandler(Handlers me) {}
}

View File

@ -1,11 +0,0 @@
package com.xuxueli.executor.sample.jfinal.controller;
import com.jfinal.core.Controller;
public class IndexController extends Controller {
public void index(){
renderText("xxl job executor running.");
}
}

View File

@ -1,54 +0,0 @@
package com.xuxueli.executor.sample.jfinal.jobhandler;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobLogger;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
/**
* 命令行任务
*
* @author xuxueli 2018-09-16 03:48:34
*/
public class CommandJobHandler extends IJobHandler {
@Override
public ReturnT<String> execute(String param) throws Exception {
String command = param;
int exitValue = -1;
BufferedReader bufferedReader = null;
try {
// command process
Process process = Runtime.getRuntime().exec(command);
BufferedInputStream bufferedInputStream = new BufferedInputStream(process.getInputStream());
bufferedReader = new BufferedReader(new InputStreamReader(bufferedInputStream));
// command log
String line;
while ((line = bufferedReader.readLine()) != null) {
XxlJobLogger.log(line);
}
// command exit
process.waitFor();
exitValue = process.exitValue();
} catch (Exception e) {
XxlJobLogger.log(e);
} finally {
if (bufferedReader != null) {
bufferedReader.close();
}
}
if (exitValue == 0) {
return IJobHandler.SUCCESS;
} else {
return new ReturnT<String>(IJobHandler.FAIL.getCode(), "command exit value("+exitValue+") is failed");
}
}
}

View File

@ -1,32 +0,0 @@
package com.xuxueli.executor.sample.jfinal.jobhandler;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobLogger;
import java.util.concurrent.TimeUnit;
/**
* 任务Handler示例Bean模式
*
* 开发步骤
* 1继承"IJobHandler"com.xxl.job.core.handler.IJobHandler
* 2注册到执行器工厂 "JFinalCoreConfig.initXxlJobExecutor" 中手动注册注解key值对应的是调度中心新建任务的JobHandler属性的值
* 3执行日志需要通过 "XxlJobLogger.log" 打印执行日志
*
* @author xuxueli 2015-12-19 19:43:36
*/
public class DemoJobHandler extends IJobHandler {
@Override
public ReturnT<String> execute(String param) throws Exception {
XxlJobLogger.log("XXL-JOB, Hello World.");
for (int i = 0; i < 5; i++) {
XxlJobLogger.log("beat at:" + i);
TimeUnit.SECONDS.sleep(2);
}
return SUCCESS;
}
}

View File

@ -1,121 +0,0 @@
package com.xuxueli.executor.sample.jfinal.jobhandler;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobLogger;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
/**
* 跨平台Http任务
*
* @author xuxueli 2018-09-16 03:48:34
*/
public class HttpJobHandler extends IJobHandler {
@Override
public ReturnT<String> execute(String param) throws Exception {
// param parse
if (param==null || param.trim().length()==0) {
XxlJobLogger.log("param["+ param +"] invalid.");
return ReturnT.FAIL;
}
String[] httpParams = param.split("\n");
String url = null;
String method = null;
String data = null;
for (String httpParam: httpParams) {
if (httpParam.startsWith("url:")) {
url = httpParam.substring(httpParam.indexOf("url:") + 4).trim();
}
if (httpParam.startsWith("method:")) {
method = httpParam.substring(httpParam.indexOf("method:") + 7).trim().toUpperCase();
}
if (httpParam.startsWith("data:")) {
data = httpParam.substring(httpParam.indexOf("data:") + 5).trim();
}
}
// param valid
if (url==null || url.trim().length()==0) {
XxlJobLogger.log("url["+ url +"] invalid.");
return ReturnT.FAIL;
}
if (method==null || !Arrays.asList("GET", "POST").contains(method)) {
XxlJobLogger.log("method["+ method +"] invalid.");
return ReturnT.FAIL;
}
boolean isPostMethod = method.equals("POST");
// request
HttpURLConnection connection = null;
BufferedReader bufferedReader = null;
try {
// connection
URL realUrl = new URL(url);
connection = (HttpURLConnection) realUrl.openConnection();
// connection setting
connection.setRequestMethod(method);
connection.setDoOutput(isPostMethod);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setReadTimeout(5 * 1000);
connection.setConnectTimeout(3 * 1000);
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
connection.setRequestProperty("Accept-Charset", "application/json;charset=UTF-8");
// do connection
connection.connect();
// data
if (isPostMethod && data!=null && data.trim().length()>0) {
DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream());
dataOutputStream.write(data.getBytes("UTF-8"));
dataOutputStream.flush();
dataOutputStream.close();
}
// valid StatusCode
int statusCode = connection.getResponseCode();
if (statusCode != 200) {
throw new RuntimeException("Http Request StatusCode(" + statusCode + ") Invalid.");
}
// result
bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
StringBuilder result = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
result.append(line);
}
String responseMsg = result.toString();
XxlJobLogger.log(responseMsg);
return ReturnT.SUCCESS;
} catch (Exception e) {
XxlJobLogger.log(e);
return ReturnT.FAIL;
} finally {
try {
if (bufferedReader != null) {
bufferedReader.close();
}
if (connection != null) {
connection.disconnect();
}
} catch (Exception e2) {
XxlJobLogger.log(e2);
}
}
}
}

View File

@ -1,36 +0,0 @@
package com.xuxueli.executor.sample.jfinal.jobhandler;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobContext;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobLogger;
/**
* 分片广播任务
*
* @author xuxueli 2017-07-25 20:56:50
*/
public class ShardingJobHandler extends IJobHandler {
@Override
public ReturnT<String> execute(String param) throws Exception {
// 分片参数
int shardIndex = XxlJobContext.getXxlJobContext().getShardIndex();
int shardTotal = XxlJobContext.getXxlJobContext().getShardTotal();
XxlJobLogger.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);
// 业务逻辑
for (int i = 0; i < shardTotal; i++) {
if (i == shardIndex) {
XxlJobLogger.log("第 {} 片, 命中分片开始处理", i);
} else {
XxlJobLogger.log("第 {} 片, 忽略", i);
}
}
return SUCCESS;
}
}

View File

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//log4j/log4j Configuration//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" threshold="null" debug="null">
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-d{yyyy-MM-dd HH:mm:ss} xxl-job-executor-sample-jfinal [%c]-[%t]-[%M]-[%L]-[%p] %m%n"/>
</layout>
</appender>
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="file" value="/data/applogs/xxl-job/xxl-job-executor-sample-jfinal.log"/>
<param name="append" value="true"/>
<param name="encoding" value="UTF-8"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-d{yyyy-MM-dd HH:mm:ss} xxl-job-executor-sample-jfinal [%c]-[%t]-[%M]-[%L]-[%p] %m%n"/>
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</log4j:configuration>

View File

@ -1,17 +0,0 @@
### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
### xxl-job, access token
xxl.job.accessToken=
### xxl-job executor appname
xxl.job.executor.appname=xxl-job-executor-sample
### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null
xxl.job.executor.address=
### xxl-job executor server-info
xxl.job.executor.ip=
xxl.job.executor.port=9999
### xxl-job executor log-path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### xxl-job executor log-retention-days
xxl.job.executor.logretentiondays=30

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>xxl-job-executor-sample-jfinal</display-name>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>xxl-job-executor-sample-jfinal</param-value>
</context-param>
<!-- jfinal -->
<filter>
<filter-name>jfinal</filter-name>
<filter-class>com.jfinal.core.JFinalFilter</filter-class>
<init-param>
<param-name>configClass</param-name>
<param-value>com.xuxueli.executor.sample.jfinal.config.JFinalCoreConfig</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jfinal</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>

View File

@ -1,10 +1,7 @@
package com.xxl.job.executor.service.jobhandler;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobContext;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.log.XxlJobLogger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@ -22,9 +19,10 @@ import java.util.concurrent.TimeUnit;
* XxlJob开发示例Bean模式
*
* 开发步骤
* 1在Spring Bean实例中开发Job方法方式格式要求为 "public ReturnT<String> execute(String param)"
* 2为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")"注解value值对应的是调度中心新建任务的JobHandler属性的值
* 3执行日志需要通过 "XxlJobLogger.log" 打印执行日志
* 1任务开发在Spring Bean实例中开发Job方法
* 2注解配置为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")"注解value值对应的是调度中心新建任务的JobHandler属性的值
* 3执行日志需要通过 "XxlJobHelper.log" 打印执行日志
* 4任务结果默认任务结果为 "成功" 状态不需要主动设置如有诉求比如设置任务结果为失败可以通过 "XxlJobHelper.handleFail/handleSuccess" 自主设置任务结果
*
* @author xuxueli 2019-12-11 21:52:51
*/
@ -37,14 +35,14 @@ public class SampleXxlJob {
* 1简单任务示例Bean模式
*/
@XxlJob("demoJobHandler")
public ReturnT<String> demoJobHandler(String param) throws Exception {
XxlJobLogger.log("XXL-JOB, Hello World.");
public void demoJobHandler() throws Exception {
XxlJobHelper.log("XXL-JOB, Hello World.");
for (int i = 0; i < 5; i++) {
XxlJobLogger.log("beat at:" + i);
XxlJobHelper.log("beat at:" + i);
TimeUnit.SECONDS.sleep(2);
}
return ReturnT.SUCCESS;
// default success
}
@ -52,24 +50,23 @@ public class SampleXxlJob {
* 2分片广播任务
*/
@XxlJob("shardingJobHandler")
public ReturnT<String> shardingJobHandler(String param) throws Exception {
public void shardingJobHandler() throws Exception {
// 分片参数
int shardIndex = XxlJobContext.getXxlJobContext().getShardIndex();
int shardTotal = XxlJobContext.getXxlJobContext().getShardTotal();
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
XxlJobLogger.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);
XxlJobHelper.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);
// 业务逻辑
for (int i = 0; i < shardTotal; i++) {
if (i == shardIndex) {
XxlJobLogger.log("第 {} 片, 命中分片开始处理", i);
XxlJobHelper.log("第 {} 片, 命中分片开始处理", i);
} else {
XxlJobLogger.log("第 {} 片, 忽略", i);
XxlJobHelper.log("第 {} 片, 忽略", i);
}
}
return ReturnT.SUCCESS;
}
@ -77,28 +74,34 @@ public class SampleXxlJob {
* 3命令行任务
*/
@XxlJob("commandJobHandler")
public ReturnT<String> commandJobHandler(String param) throws Exception {
String command = param;
public void commandJobHandler() throws Exception {
String command = XxlJobHelper.getJobParam();
int exitValue = -1;
BufferedReader bufferedReader = null;
try {
// command process
Process process = Runtime.getRuntime().exec(command);
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command(command);
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
//Process process = Runtime.getRuntime().exec(command);
BufferedInputStream bufferedInputStream = new BufferedInputStream(process.getInputStream());
bufferedReader = new BufferedReader(new InputStreamReader(bufferedInputStream));
// command log
String line;
while ((line = bufferedReader.readLine()) != null) {
XxlJobLogger.log(line);
XxlJobHelper.log(line);
}
// command exit
process.waitFor();
exitValue = process.exitValue();
} catch (Exception e) {
XxlJobLogger.log(e);
XxlJobHelper.log(e);
} finally {
if (bufferedReader != null) {
bufferedReader.close();
@ -106,10 +109,11 @@ public class SampleXxlJob {
}
if (exitValue == 0) {
return IJobHandler.SUCCESS;
// default success
} else {
return new ReturnT<String>(IJobHandler.FAIL.getCode(), "command exit value("+exitValue+") is failed");
XxlJobHelper.handleFail("command exit value("+exitValue+") is failed");
}
}
@ -121,13 +125,17 @@ public class SampleXxlJob {
* "data: content\n";
*/
@XxlJob("httpJobHandler")
public ReturnT<String> httpJobHandler(String param) throws Exception {
public void httpJobHandler() throws Exception {
// param parse
String param = XxlJobHelper.getJobParam();
if (param==null || param.trim().length()==0) {
XxlJobLogger.log("param["+ param +"] invalid.");
return ReturnT.FAIL;
XxlJobHelper.log("param["+ param +"] invalid.");
XxlJobHelper.handleFail();
return;
}
String[] httpParams = param.split("\n");
String url = null;
String method = null;
@ -146,12 +154,16 @@ public class SampleXxlJob {
// param valid
if (url==null || url.trim().length()==0) {
XxlJobLogger.log("url["+ url +"] invalid.");
return ReturnT.FAIL;
XxlJobHelper.log("url["+ url +"] invalid.");
XxlJobHelper.handleFail();
return;
}
if (method==null || !Arrays.asList("GET", "POST").contains(method)) {
XxlJobLogger.log("method["+ method +"] invalid.");
return ReturnT.FAIL;
XxlJobHelper.log("method["+ method +"] invalid.");
XxlJobHelper.handleFail();
return;
}
boolean isPostMethod = method.equals("POST");
@ -200,11 +212,14 @@ public class SampleXxlJob {
}
String responseMsg = result.toString();
XxlJobLogger.log(responseMsg);
return ReturnT.SUCCESS;
XxlJobHelper.log(responseMsg);
return;
} catch (Exception e) {
XxlJobLogger.log(e);
return ReturnT.FAIL;
XxlJobHelper.log(e);
XxlJobHelper.handleFail();
return;
} finally {
try {
if (bufferedReader != null) {
@ -214,7 +229,7 @@ public class SampleXxlJob {
connection.disconnect();
}
} catch (Exception e2) {
XxlJobLogger.log(e2);
XxlJobHelper.log(e2);
}
}
@ -224,9 +239,8 @@ public class SampleXxlJob {
* 5生命周期任务示例任务初始化与销毁时支持自定义相关逻辑
*/
@XxlJob(value = "demoJobHandler2", init = "init", destroy = "destroy")
public ReturnT<String> demoJobHandler2(String param) throws Exception {
XxlJobLogger.log("XXL-JOB, Hello World.");
return ReturnT.SUCCESS;
public void demoJobHandler2() throws Exception {
XxlJobHelper.log("XXL-JOB, Hello World.");
}
public void init(){
logger.info("init");

View File

@ -1,10 +1,7 @@
package com.xxl.job.executor.service.jobhandler;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobContext;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.log.XxlJobLogger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@ -22,9 +19,10 @@ import java.util.concurrent.TimeUnit;
* XxlJob开发示例Bean模式
*
* 开发步骤
* 1在Spring Bean实例中开发Job方法方式格式要求为 "public ReturnT<String> execute(String param)"
* 2为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")"注解value值对应的是调度中心新建任务的JobHandler属性的值
* 3执行日志需要通过 "XxlJobLogger.log" 打印执行日志
* 1任务开发在Spring Bean实例中开发Job方法
* 2注解配置为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")"注解value值对应的是调度中心新建任务的JobHandler属性的值
* 3执行日志需要通过 "XxlJobHelper.log" 打印执行日志
* 4任务结果默认任务结果为 "成功" 状态不需要主动设置如有诉求比如设置任务结果为失败可以通过 "XxlJobHelper.handleFail/handleSuccess" 自主设置任务结果
*
* @author xuxueli 2019-12-11 21:52:51
*/
@ -37,14 +35,14 @@ public class SampleXxlJob {
* 1简单任务示例Bean模式
*/
@XxlJob("demoJobHandler")
public ReturnT<String> demoJobHandler(String param) throws Exception {
XxlJobLogger.log("XXL-JOB, Hello World.");
public void demoJobHandler() throws Exception {
XxlJobHelper.log("XXL-JOB, Hello World.");
for (int i = 0; i < 5; i++) {
XxlJobLogger.log("beat at:" + i);
XxlJobHelper.log("beat at:" + i);
TimeUnit.SECONDS.sleep(2);
}
return ReturnT.SUCCESS;
// default success
}
@ -52,24 +50,23 @@ public class SampleXxlJob {
* 2分片广播任务
*/
@XxlJob("shardingJobHandler")
public ReturnT<String> shardingJobHandler(String param) throws Exception {
public void shardingJobHandler() throws Exception {
// 分片参数
int shardIndex = XxlJobContext.getXxlJobContext().getShardIndex();
int shardTotal = XxlJobContext.getXxlJobContext().getShardTotal();
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
XxlJobLogger.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);
XxlJobHelper.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);
// 业务逻辑
for (int i = 0; i < shardTotal; i++) {
if (i == shardIndex) {
XxlJobLogger.log("第 {} 片, 命中分片开始处理", i);
XxlJobHelper.log("第 {} 片, 命中分片开始处理", i);
} else {
XxlJobLogger.log("第 {} 片, 忽略", i);
XxlJobHelper.log("第 {} 片, 忽略", i);
}
}
return ReturnT.SUCCESS;
}
@ -77,8 +74,8 @@ public class SampleXxlJob {
* 3命令行任务
*/
@XxlJob("commandJobHandler")
public ReturnT<String> commandJobHandler(String param) throws Exception {
String command = param;
public void commandJobHandler() throws Exception {
String command = XxlJobHelper.getJobParam();
int exitValue = -1;
BufferedReader bufferedReader = null;
@ -97,14 +94,14 @@ public class SampleXxlJob {
// command log
String line;
while ((line = bufferedReader.readLine()) != null) {
XxlJobLogger.log(line);
XxlJobHelper.log(line);
}
// command exit
process.waitFor();
exitValue = process.exitValue();
} catch (Exception e) {
XxlJobLogger.log(e);
XxlJobHelper.log(e);
} finally {
if (bufferedReader != null) {
bufferedReader.close();
@ -112,10 +109,11 @@ public class SampleXxlJob {
}
if (exitValue == 0) {
return IJobHandler.SUCCESS;
// default success
} else {
return new ReturnT<String>(IJobHandler.FAIL.getCode(), "command exit value("+exitValue+") is failed");
XxlJobHelper.handleFail("command exit value("+exitValue+") is failed");
}
}
@ -127,13 +125,17 @@ public class SampleXxlJob {
* "data: content\n";
*/
@XxlJob("httpJobHandler")
public ReturnT<String> httpJobHandler(String param) throws Exception {
public void httpJobHandler() throws Exception {
// param parse
String param = XxlJobHelper.getJobParam();
if (param==null || param.trim().length()==0) {
XxlJobLogger.log("param["+ param +"] invalid.");
return ReturnT.FAIL;
XxlJobHelper.log("param["+ param +"] invalid.");
XxlJobHelper.handleFail();
return;
}
String[] httpParams = param.split("\n");
String url = null;
String method = null;
@ -152,12 +154,16 @@ public class SampleXxlJob {
// param valid
if (url==null || url.trim().length()==0) {
XxlJobLogger.log("url["+ url +"] invalid.");
return ReturnT.FAIL;
XxlJobHelper.log("url["+ url +"] invalid.");
XxlJobHelper.handleFail();
return;
}
if (method==null || !Arrays.asList("GET", "POST").contains(method)) {
XxlJobLogger.log("method["+ method +"] invalid.");
return ReturnT.FAIL;
XxlJobHelper.log("method["+ method +"] invalid.");
XxlJobHelper.handleFail();
return;
}
boolean isPostMethod = method.equals("POST");
@ -206,11 +212,14 @@ public class SampleXxlJob {
}
String responseMsg = result.toString();
XxlJobLogger.log(responseMsg);
return ReturnT.SUCCESS;
XxlJobHelper.log(responseMsg);
return;
} catch (Exception e) {
XxlJobLogger.log(e);
return ReturnT.FAIL;
XxlJobHelper.log(e);
XxlJobHelper.handleFail();
return;
} finally {
try {
if (bufferedReader != null) {
@ -220,7 +229,7 @@ public class SampleXxlJob {
connection.disconnect();
}
} catch (Exception e2) {
XxlJobLogger.log(e2);
XxlJobHelper.log(e2);
}
}
@ -230,9 +239,8 @@ public class SampleXxlJob {
* 5生命周期任务示例任务初始化与销毁时支持自定义相关逻辑
*/
@XxlJob(value = "demoJobHandler2", init = "init", destroy = "destroy")
public ReturnT<String> demoJobHandler2(String param) throws Exception {
XxlJobLogger.log("XXL-JOB, Hello World.");
return ReturnT.SUCCESS;
public void demoJobHandler2() throws Exception {
XxlJobHelper.log("XXL-JOB, Hello World.");
}
public void init(){
logger.info("init");