瀏覽代碼

完善 JobHandlerInvoker 的执行,记录 Job 执行日志

YunaiV 4 年之前
父節點
當前提交
5fc03bd8aa

+ 72 - 8
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<String> 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) {

+ 43 - 0
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);
+
+}

+ 4 - 21
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()} 属性
-     */
-    private String resultMsg;
-    /**
-     * 结果数据
+     * 结果
      *
-     * 目前使用的 {@link CommonResult#getData()} 数据
+     * 成功时,使用 {@link CommonResult#getData()} 数据
+     * 失败时,使用 {@link CommonResult#getMsg()} 属性
      */
-    private String resultData;
+    private String result;
 
 }

+ 4 - 0
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();
+    }
+
 }