diff --git a/src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandlerInvoker.java b/src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandlerInvoker.java index b5ab7e019..ea9f81b39 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandlerInvoker.java +++ b/src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandlerInvoker.java @@ -1,39 +1,103 @@ 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; import org.quartz.DisallowConcurrentExecution; import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; import org.quartz.PersistJobDataAfterExecution; import org.springframework.context.ApplicationContext; 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; /** * 基础 Job 调用者,负责调用 {@link JobHandler#execute(String)} 执行任务 * * @author 芋道源码 */ -@PersistJobDataAfterExecution @DisallowConcurrentExecution +@PersistJobDataAfterExecution +@Slf4j public class JobHandlerInvoker extends QuartzJobBean { @Resource private ApplicationContext applicationContext; + @Resource + private JobLogFrameworkService jobLogFrameworkService; + @Override - protected void executeInternal(JobExecutionContext executionContext) { - // 获得 JobHandler 对象 + 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)); + } + Long jobId = Long.valueOf(jobIdStr); + // 2. 获得 jobHandlerName 参数 String jobHandlerName = getJobData(executionContext, JobDataKeyEnum.JOB_HANDLER_NAME); + if (StrUtil.isEmpty(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); + } + } + + private String executeInternal(Long jobId, String jobHandlerName, String jobHandlerParam) throws Exception { + // 获得 JobHandler 对象 JobHandler jobHandler = applicationContext.getBean(jobHandlerName, JobHandler.class); + Assert.isNull(jobHandler, "JobHandler 不会为空"); // 执行任务 - String jobParam = getJobData(executionContext, JobDataKeyEnum.JOB_HANDLER_PARAM); - try { - jobHandler.execute(jobParam); - } catch (Exception e) { - // TODO 需要后续处理 + CommonResult result = jobHandler.execute(jobHandlerParam); + // 如果执行失败,则抛出 ServiceException 异常,方便统一记录 + if (result.isError()) { + throw new ServiceException(result.getCode(), result.getMsg()); } + return result.getData(); } private static String getJobData(JobExecutionContext executionContext, JobDataKeyEnum key) { diff --git a/src/main/java/cn/iocoder/dashboard/framework/quartz/core/service/JobLogFrameworkService.java b/src/main/java/cn/iocoder/dashboard/framework/quartz/core/service/JobLogFrameworkService.java new file mode 100644 index 000000000..910dc06b3 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/quartz/core/service/JobLogFrameworkService.java @@ -0,0 +1,43 @@ +package cn.iocoder.dashboard.framework.quartz.core.service; + +import java.util.Date; + +/** + * Job 日志 Framework Service 接口 + * + * @author 芋道源码 + */ +public interface JobLogFrameworkService { + + /** + * 创建 Job 日志 + * + * @param jobId 任务编号 + * @param jobHandlerName Job 处理器的名字 + * @param jobHandlerParam Job 处理器的参数 + * @return Job 日志的编号 + */ + Long createJobLog(Long jobId, String jobHandlerName, String jobHandlerParam); + + /** + * 更新 Job 日志成功 + * + * @param id 日志编号 + * @param endTime 结束时间。因为是异步,避免记录时间不准去 + * @param duration 运行时长,单位:毫秒 + * @param data 成功数据 + */ + void updateJobLogSuccessAsync(Long id, Date endTime, Long duration, String data); + + /** + * 更新 Job 日志失败 + * + * @param id 日志编号 + * @param endTime 结束时间。因为是异步,避免记录时间不准去 + * @param duration 运行时长,单位:毫秒 + * @param code 错误码 + * @param msg 异常提示 + */ + void updateJobLogErrorAsync(Long id, Date endTime, Long duration, Integer code, String msg); + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/job/InfJobLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/job/InfJobLogDO.java index c71d147e5..cead55665 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/job/InfJobLogDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/job/InfJobLogDO.java @@ -30,18 +30,6 @@ public class InfJobLogDO extends BaseDO { * 关联 {@link InfJobDO#getId()} */ private Long jobId; - /** - * 任务名称 - * - * 冗余字段 {@link InfJobDO#getName()} - */ - private String jobName; - /** - * 任务分组 - * - * 冗余字段 {@link InfJobDO#getGroup()} - */ - private String jobGroup; /** * 处理器的名字 * @@ -74,16 +62,11 @@ public class InfJobLogDO extends BaseDO { */ private Integer resultCode; /** - * 结果提示 + * 结果 * - * 目前使用的 {@link CommonResult#getMsg()} 属性 + * 成功时,使用 {@link CommonResult#getData()} 数据 + * 失败时,使用 {@link CommonResult#getMsg()} 属性 */ - private String resultMsg; - /** - * 结果数据 - * - * 目前使用的 {@link CommonResult#getData()} 数据 - */ - private String resultData; + private String result; } diff --git a/src/main/java/cn/iocoder/dashboard/util/date/DateUtils.java b/src/main/java/cn/iocoder/dashboard/util/date/DateUtils.java index d0f80089f..7e1ce6650 100644 --- a/src/main/java/cn/iocoder/dashboard/util/date/DateUtils.java +++ b/src/main/java/cn/iocoder/dashboard/util/date/DateUtils.java @@ -18,4 +18,8 @@ public class DateUtils { return System.currentTimeMillis() > time.getTime(); } + public static Long diff(Date endTime, Date startTime) { + return endTime.getTime() - startTime.getTime(); + } + }