本文基于xxl-job的2.3.1版本
执行器,即任务逻辑代码所在的服务,也就是你的业务项目,由调度中心的触发器通过网络请求,调用执行的任务执行
在获取执行器客户端时,会根据指定的地址获取执行器客户端,如果执行器未初始化,会初始化一个执行器
com.xxl.job.admin.core.scheduler.XxlJobScheduler
public static ExecutorBiz getExecutorBiz(String address) {
// valid
if (address == null || address.trim().length() == 0) {
return null;
}
// load-cache
address = address.trim();
ExecutorBiz executorBiz = executorBizRepository.get(address);
if (executorBiz != null) {
return executorBiz;
}
// set-cache
executorBiz = new ExecutorBizClient(address, XxlJobAdminConfig.getAdminConfig().getAccessToken());
executorBizRepository.put(address, executorBiz);
return executorBiz;
}
通过该接口定义调度中心对客户端发起的一系列请求,其中run方法就是执行任务。
com.xxl.job.core.biz.ExecutorBiz
/**
* 执行器心跳
* 用于 路由策略-故障转移 的执行器心跳检查
*
* @return 处理结果
*/
ReturnT<String> beat();
/**
* 闲置心跳检查(执行中或在队列中属于非闲置状态)
* 用于 路由策略-忙碌转移 检查非闲置节点
*
* @param idleBeatParam 参数(仅任务ID)
* @return 是否闲置
*/
ReturnT<String> idleBeat(IdleBeatParam idleBeatParam);
/**
* 任务执行
* 调度中心任务触发
*
* @param triggerParam 执行参数
* @return 处理结果
*/
ReturnT<String> run(TriggerParam triggerParam);
/**
* 终止任务执行(删除任务的执行线程)
* 用于页面操作终止任务
*
* @param killParam 参数(仅任务ID)
* @return 处理结果
*/
ReturnT<String> kill(KillParam killParam);
/**
* 日志内容读取
* 用于页面读取日志
*
* @param logParam 读取参数(日志ID, 起始行, 日志日期)
* @return 日志读取结果(日志内容, 结束行等)
*/
ReturnT<LogResult> log(LogParam logParam);
该接口有两个实现类:
com.xxl.job.core.biz.client.ExecutorBizClient
调度中心使用的执行器客户端
com.xxl.job.core.biz.impl.ExecutorBizImpl
执行器所在应用处理任务调度请求的实现类
调度器Trigger中根据配置选定执行器客户端之后,调用客户端的run方法,发出http请求
com.xxl.job.admin.core.trigger.XxlJobTrigger
/**
* 触发任务执行
*
* @param triggerParam 任务参数
* @param address 执行器地址
* @return 执行结果
*/
public static ReturnT<String> runExecutor(TriggerParam triggerParam, String address) {
ReturnT<String> runResult;
try {
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address);
runResult = executorBiz.run(triggerParam);
} catch (Exception e) {
logger.error(">>>>>>>>>>> xxl-job trigger error, please check if the executor[{}] is running.", address, e);
runResult = new ReturnT<>(ReturnT.FAIL_CODE, ThrowableUtil.toString(e));
}
String runResultSB = I18nUtil.getString("jobconf_trigger_run") + ":" + "
address:" + address +
"
code:" + runResult.getCode() +
"
msg:" + runResult.getMsg();
runResult.setMsg(runResultSB);
return runResult;
}
com.xxl.job.core.biz.client.ExecutorBizClient
@Override
public ReturnT<String> run(TriggerParam triggerParam) {
return XxlJobRemotingUtil.postBody(addressUrl + "run", accessToken, DEFAULT_TIMEOUT, triggerParam, String.class);
}
这里 XxlJobRemotingUt
通过HttpURLConnection
发起HTTP请求到执行中,由执行器中的 EmbedServer
接受请求
接收调度中心发送的请求的 rpc客户端也是由作者依赖netty实现 https://github.com/xuxueli/xxl-rpc
这里不细究具体的客户端实现,看下请求的分发调用。
接受到请求之后,根据路由区分调用 ExecutorBizImpl
的方法
com.xxl.job.core.server.EmbedServer
private Object process(HttpMethod httpMethod, String uri, String requestData, String accessTokenReq) {
// valid
if (HttpMethod.POST != httpMethod) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, HttpMethod not support.");
}
if (uri == null || uri.trim().length() == 0) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping empty.");
}
if (accessToken != null
&& accessToken.trim().length() > 0
&& !accessToken.equals(accessTokenReq)) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "The access token is wrong.");
}
// services mapping
try {
switch (uri) {
case "/beat":
return executorBiz.beat();
case "/idleBeat":
IdleBeatParam idleBeatParam = GsonTool.fromJson(requestData, IdleBeatParam.class);
return executorBiz.idleBeat(idleBeatParam);
case "/run":
TriggerParam triggerParam = GsonTool.fromJson(requestData, TriggerParam.class);
return executorBiz.run(triggerParam);
case "/kill":
KillParam killParam = GsonTool.fromJson(requestData, KillParam.class);
return executorBiz.kill(killParam);
case "/log":
LogParam logParam = GsonTool.fromJson(requestData, LogParam.class);
return executorBiz.log(logParam);
default:
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping(" + uri + ") not found.");
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new ReturnT<String>(ReturnT.FAIL_CODE, "request error:" + ThrowableUtil.toString(e));
}
}