1. 同步最新的表结构

2. 记录执行日志
This commit is contained in:
YunaiV
2021-02-17 21:00:58 +08:00
parent 5fc03bd8aa
commit 74f2c8a879
11 changed files with 271 additions and 83 deletions

View File

@ -1,7 +1,5 @@
package cn.iocoder.dashboard.framework.quartz.core.handler;
import cn.iocoder.dashboard.common.pojo.CommonResult;
/**
* 任务处理器
*
@ -16,6 +14,6 @@ public interface JobHandler {
* @return 结果
* @throws Exception 异常
*/
CommonResult<String> execute(String param) throws Exception;
String execute(String param) throws Exception;
}

View File

@ -1,11 +1,7 @@
package cn.iocoder.dashboard.framework.quartz.core.handler;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.common.exception.ServiceException;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.quartz.core.enums.JobDataKeyEnum;
import cn.iocoder.dashboard.framework.quartz.core.service.JobLogFrameworkService;
import lombok.extern.slf4j.Slf4j;
@ -19,8 +15,8 @@ import org.springframework.scheduling.quartz.QuartzJobBean;
import javax.annotation.Resource;
import java.util.Date;
import static cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
import static cn.iocoder.dashboard.util.date.DateUtils.diff;
import static org.apache.commons.lang3.exception.ExceptionUtils.getRootCauseMessage;
/**
* 基础 Job 调用者,负责调用 {@link JobHandler#execute(String)} 执行任务
@ -40,68 +36,68 @@ public class JobHandlerInvoker extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext executionContext) throws JobExecutionException {
// 获得 Job 数据
// 1. 获得 jobId 参数
String jobIdStr = getJobData(executionContext, JobDataKeyEnum.JOB_ID);
if (NumberUtil.isNumber(jobIdStr)) {
log.error("[executeInternal][Job({}) 获取不到正确的 jobId({})]", executionContext.getJobDetail().getKey(), jobIdStr);
throw new IllegalStateException(StrUtil.format("Job({}) 获取不到正确的 jobId({})",
executionContext.getJobDetail().getKey(), jobIdStr));
// 第一步,获得 Job 数据
Long jobId = executionContext.getMergedJobDataMap().getLong(JobDataKeyEnum.JOB_ID.name());
String jobHandlerName = getJobHandlerName(executionContext);
String jobHandlerParam = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_PARAM.name());
// 第二步,执行任务
Long jobLogId = null;
Date startTime = new Date();
String data = null;
Throwable exception = null;
try {
// 记录 Job 日志(初始)
jobLogId = jobLogFrameworkService.createJobLog(jobId, startTime, jobHandlerName, jobHandlerParam);
// 执行任务
data = this.executeInternal(jobHandlerName, jobHandlerParam);
} catch (Throwable ex) {
exception = ex;
}
Long jobId = Long.valueOf(jobIdStr);
// 2. 获得 jobHandlerName 参数
String jobHandlerName = getJobData(executionContext, JobDataKeyEnum.JOB_HANDLER_NAME);
// 第三步,记录执行日志
this.updateJobLogResultAsync(jobLogId, startTime, data, exception, executionContext);
// 最终还是抛出异常,用于停止任务
if (exception != null) {
throw new JobExecutionException(exception);
}
}
private static String getJobHandlerName(JobExecutionContext executionContext) {
String jobHandlerName = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_NAME.name());
if (StrUtil.isEmpty(jobHandlerName)) {
log.error("[executeInternal][Job({}) 获取不到正确的 jobHandlerName({})]", executionContext.getJobDetail().getKey(), jobHandlerName);
log.error("[executeInternal][Job({}) 获取不到正确的 jobHandlerName({})]",
executionContext.getJobDetail().getKey(), jobHandlerName);
throw new IllegalStateException(StrUtil.format("Job({}) 获取不到正确的 jobHandlerName({})",
executionContext.getJobDetail().getKey(), jobHandlerName));
}
// 3. 获得 jobHandlerParam 参数
String jobHandlerParam = getJobData(executionContext, JobDataKeyEnum.JOB_HANDLER_PARAM);
Long jobLogId = null;
Date startTime = new Date();
try {
// 记录 Job 日志(初始)
jobLogId = jobLogFrameworkService.createJobLog(jobId, jobHandlerName, jobHandlerParam);
// 执行任务
String data = this.executeInternal(jobId, jobHandlerName, jobHandlerParam);
// 标记 Job 日志(成功)
Date endTime = new Date();
jobLogFrameworkService.updateJobLogSuccessAsync(jobLogId, endTime, diff(endTime, startTime), data);
} catch (ServiceException serviceException) {
// 标记 Job 日志(异常)
Date endTime = new Date();
jobLogFrameworkService.updateJobLogErrorAsync(jobLogId, endTime, diff(endTime, startTime),
serviceException.getCode(), serviceException.getMessage());
// 最终还是抛出异常,用于停止任务
throw serviceException;
} catch (Throwable e) {
// 标记 Job 日志(异常)
Date endTime = new Date();
jobLogFrameworkService.updateJobLogErrorAsync(jobLogId, endTime, diff(endTime, startTime),
INTERNAL_SERVER_ERROR.getCode(), ExceptionUtil.getRootCauseMessage(e));
// 最终还是抛出异常,用于停止任务
throw new JobExecutionException(e);
}
return jobHandlerName;
}
private String executeInternal(Long jobId, String jobHandlerName, String jobHandlerParam) throws Exception {
private String executeInternal(String jobHandlerName, String jobHandlerParam) throws Exception {
// 获得 JobHandler 对象
JobHandler jobHandler = applicationContext.getBean(jobHandlerName, JobHandler.class);
Assert.isNull(jobHandler, "JobHandler 不会为空");
Assert.notNull(jobHandler, "JobHandler 不会为空");
// 执行任务
CommonResult<String> result = jobHandler.execute(jobHandlerParam);
// 如果执行失败,则抛出 ServiceException 异常,方便统一记录
if (result.isError()) {
throw new ServiceException(result.getCode(), result.getMsg());
}
return result.getData();
return jobHandler.execute(jobHandlerParam);
}
private static String getJobData(JobExecutionContext executionContext, JobDataKeyEnum key) {
return executionContext.getMergedJobDataMap().getString(key.name());
private void updateJobLogResultAsync(Long jobLogId, Date startTime, String data, Throwable exception,
JobExecutionContext executionContext) {
Date endTime = new Date();
try {
if (data != null) { // 成功
jobLogFrameworkService.updateJobLogSuccessAsync(jobLogId, endTime, (int) diff(endTime, startTime), data);
} else { // 失败
jobLogFrameworkService.updateJobLogErrorAsync(jobLogId, endTime, (int) diff(endTime, startTime),
getRootCauseMessage(exception));
}
} catch (Exception ex) {
log.error("[executeInternal][Job({}) logId({}) 记录执行日志失败({})]",
executionContext.getJobDetail().getKey(), jobLogId,
data != null ? data : getRootCauseMessage(exception));
}
}
}

View File

@ -1,5 +1,7 @@
package cn.iocoder.dashboard.framework.quartz.core.service;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
@ -13,31 +15,40 @@ public interface JobLogFrameworkService {
* 创建 Job 日志
*
* @param jobId 任务编号
* @param beginTime 开始时间
* @param jobHandlerName Job 处理器的名字
* @param jobHandlerParam Job 处理器的参数
* @return Job 日志的编号
*/
Long createJobLog(Long jobId, String jobHandlerName, String jobHandlerParam);
Long createJobLog(@NotNull(message = "任务编号不能为空") Long jobId,
@NotNull(message = "开始时间") Date beginTime,
@NotEmpty(message = "Job 处理器的名字不能为空") String jobHandlerName,
String jobHandlerParam);
/**
* 更新 Job 日志成功
*
* @param id 日志编号
* @param logId 日志编号
* @param endTime 结束时间。因为是异步,避免记录时间不准去
* @param duration 运行时长,单位:毫秒
* @param data 成功数据
* @param result 成功数据
*/
void updateJobLogSuccessAsync(Long id, Date endTime, Long duration, String data);
void updateJobLogSuccessAsync(@NotNull(message = "日志编号不能为空") Long logId,
@NotNull(message = "结束时间不能为空") Date endTime,
@NotNull(message = "运行时长不能为空") Integer duration,
String result);
/**
* 更新 Job 日志失败
*
* @param id 日志编号
* @param logId 日志编号
* @param endTime 结束时间。因为是异步,避免记录时间不准去
* @param duration 运行时长,单位:毫秒
* @param code 错误码
* @param msg 异常提示
* @param result 异常提示
*/
void updateJobLogErrorAsync(Long id, Date endTime, Long duration, Integer code, String msg);
void updateJobLogErrorAsync(@NotNull(message = "日志编号不能为空") Long logId,
@NotNull(message = "结束时间不能为空") Date endTime,
@NotNull(message = "运行时长不能为空") Integer duration,
String result);
}