com.github.hengboy.job.schedule.runnable.MicroJobExecuteRunnable Maven / Gradle / Ivy
/*
* Copyright [2019] [恒宇少年 - 于起宇]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.hengboy.job.schedule.runnable;
import com.alibaba.fastjson.JSON;
import com.github.hengboy.job.core.enums.JobExecuteStatusEnum;
import com.github.hengboy.job.core.enums.LoadBalanceStrategy;
import com.github.hengboy.job.core.http.MicroJobRestTemplate;
import com.github.hengboy.job.core.http.RestUrlConstants;
import com.github.hengboy.job.core.http.RestUrlTools;
import com.github.hengboy.job.core.model.execute.JobExecuteParam;
import com.github.hengboy.job.core.model.execute.JobExecuteResult;
import com.github.hengboy.job.core.strategy.LbStrategy;
import com.github.hengboy.job.core.strategy.LbStrategyFactory;
import com.github.hengboy.job.schedule.quartz.QuartzJobContext;
import com.github.hengboy.job.schedule.queue.bean.JobQueueBean;
import com.github.hengboy.job.schedule.resource.MicroJobScheduleResource;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
/**
* 任务执行线程
*
* @author:恒宇少年 - 于起宇
*
* DateTime:2019-01-31 13:12
* Blog:http://blog.yuqiyu.com
* WebSite:http://www.jianshu.com/u/092df3f77bca
* Gitee:https://gitee.com/hengboy
* GitHub:https://github.com/hengyuboy
*/
@AllArgsConstructor
public class MicroJobExecuteRunnable implements Runnable {
/**
* logger instance
*/
static Logger logger = LoggerFactory.getLogger(MicroJobExecuteRunnable.class);
/**
* 本次任务执行的对象
*/
private JobQueueBean jobQueueBean;
@Override
public void run() {
try {
// 获取负载方式的实现
LbStrategy lbStrategy = LbStrategyFactory.getStrategy(LoadBalanceStrategy.valueOf(jobQueueBean.getLbStrategy()));
// 初始化参与负载的节点
lbStrategy.initJoinNodes(MicroJobScheduleResource.getAllConsumerLbNode());
// 不同负载方式获取到的负载任务节点不同
String loadBalanceConsumerAddress = lbStrategy.select(jobQueueBean.getJobQueueKey());
if (loadBalanceConsumerAddress != null) {
logger.info("Use Node:[{}] execute job [{}]", loadBalanceConsumerAddress, jobQueueBean.getJobQueueKey());
// 远程执行实例
MicroJobRestTemplate restTemplate = MicroJobScheduleResource.getRestTemplate();
// 任务执行参数
JobExecuteParam jobExecuteParam = new JobExecuteParam(jobQueueBean.getJobKey(), jobQueueBean.getJobQueueId(), jobQueueBean.getJobExecuteParam());
// 处理消费者地址
String[] consumerAddress = loadBalanceConsumerAddress.split(":");
// 格式化请求路径
String executeJobUrl = RestUrlTools.formatter(consumerAddress[0], Integer.valueOf(consumerAddress[1]), RestUrlConstants.CONSUMER_EXECUTE_JOB_FULL_URL);
// 执行任务
JobExecuteResult jobExecuteResult = restTemplate.postJsonEntity(executeJobUrl, JSON.toJSONString(jobExecuteParam), HttpHeaders.EMPTY, JobExecuteResult.class);
// 任务执行完后逻辑
// 1. 回收
// 2. 成功
// 3. 更新执行详情
jobExecuteAfter(jobQueueBean, jobExecuteResult, loadBalanceConsumerAddress);
}
// 更新状态为重试
else {
MicroJobScheduleResource.getJobStore().updateJobState(jobQueueBean.getExecuteLogId(), JobExecuteStatusEnum.RETRY.toString());
// 任务回收,放入重试队列
jobRecovery(jobQueueBean);
}
} catch (Exception e) {
logger.error("Execute job :" + jobQueueBean.getJobQueueKey() + "error", e);
jobRecovery(jobQueueBean);
}
}
/**
* 任务回收
*
* @param jobQueueBean
*/
private void jobRecovery(JobQueueBean jobQueueBean) {
try {
MicroJobScheduleResource.JOB_RECOVERY_RETRY_QUEUE.put(jobQueueBean);
if (jobQueueBean.getRetryCount() < MicroJobScheduleResource.getMaxRetryTimes()) {
logger.warn("Job:[{}] recovery completion", jobQueueBean.getJobQueueKey());
} else {
logger.error("Job:[{}] upper limit of retries , recovery ignore", jobQueueBean.getJobQueueKey());
}
} catch (InterruptedException ex) {
logger.info("Job:[{}] recovery error", jobQueueBean.getJobQueueKey());
ex.printStackTrace();
}
}
/**
* 远程任务执行完成后
* 1. 回收
* 2. 成功
* 3. 更新执行详情
*
* @param jobExecuteResult 远程执行结果
* @param jobQueueBean 任务执行详情
*/
private void jobExecuteAfter(JobQueueBean jobQueueBean, JobExecuteResult jobExecuteResult, String loadBalanceConsumerAddress) {
try {
// 任务执行状态,默认成功
JobExecuteStatusEnum jobExecuteStatusEnum = JobExecuteStatusEnum.SUCCESS;
switch (jobExecuteResult.getCode()) {
case SUCCESS:
// 更新成功时间
MicroJobScheduleResource.getJobStore().updateJobExecuteSuccessTime(jobQueueBean.getExecuteLogId());
break;
case ERROR:
case RETRY:
// 更新状态为重试
jobExecuteStatusEnum = JobExecuteStatusEnum.RETRY;
break;
// 删除执行的任务
case REMOVE:
QuartzJobContext.removeJob(MicroJobScheduleResource.getScheduler(), jobQueueBean.getJobQueueId(), jobQueueBean.getJobKey());
break;
default:
// 更新状态为重试
jobExecuteStatusEnum = JobExecuteStatusEnum.RETRY;
break;
}
// 放入重试队列
if (JobExecuteStatusEnum.RETRY.equals(jobExecuteStatusEnum)) {
// 任务回收
jobRecovery(jobQueueBean);
}
// 更新状态
MicroJobScheduleResource.getJobStore().updateJobState(jobQueueBean.getExecuteLogId(), jobExecuteStatusEnum.toString());
// 更新任务消费的消费者地址
MicroJobScheduleResource.getJobStore().updateJobExecuteConsumer(jobQueueBean.getExecuteLogId(), loadBalanceConsumerAddress);
} catch (Exception e) {
logger.error("Failure of subsequent logical processing for task execution", e);
}
}
}