完成 xxl-job 的接入
parent
4381d938be
commit
3774afe553
|
@ -34,6 +34,7 @@
|
|||
<!-- Config 配置中心相关 -->
|
||||
<apollo.version>1.9.2</apollo.version>
|
||||
<!-- Job 定时任务相关 -->
|
||||
<xxl-job.version>2.3.1</xxl-job.version>
|
||||
<!-- 服务保障相关 -->
|
||||
<lock4j.version>2.2.0</lock4j.version>
|
||||
<resilience4j.version>1.7.1</resilience4j.version>
|
||||
|
@ -251,6 +252,11 @@
|
|||
<!-- Config 配置中心相关 -->
|
||||
|
||||
<!-- Job 定时任务相关 -->
|
||||
<dependency>
|
||||
<groupId>com.xuxueli</groupId>
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
<version>${xxl-job.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-job</artifactId>
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
package cn.iocoder.yudao.framework.tenant.config;
|
||||
|
||||
import cn.hutool.core.annotation.AnnotationUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
||||
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
|
||||
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor;
|
||||
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
|
||||
import cn.iocoder.yudao.framework.tenant.core.job.TenantJobHandlerDecorator;
|
||||
import cn.iocoder.yudao.framework.tenant.core.job.TenantJobAspect;
|
||||
import cn.iocoder.yudao.framework.tenant.core.mq.TenantChannelInterceptor;
|
||||
import cn.iocoder.yudao.framework.tenant.core.mq.TenantFunctionAroundWrapper;
|
||||
import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter;
|
||||
|
@ -19,6 +16,7 @@ import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
|||
import cn.iocoder.yudao.module.system.api.tenant.TenantApi;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
||||
import com.xxl.job.core.executor.XxlJobExecutor;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
|
@ -103,19 +101,25 @@ public class YudaoTenantAutoConfiguration {
|
|||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (!(bean instanceof JobHandler)) {
|
||||
if (!(bean instanceof XxlJobExecutor)) {
|
||||
return bean;
|
||||
}
|
||||
// 有 TenantJob 注解的情况下,才会进行处理
|
||||
if (!AnnotationUtil.hasAnnotation(bean.getClass(), TenantJob.class)) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
// 使用 TenantJobHandlerDecorator 装饰
|
||||
return new TenantJobHandlerDecorator(tenantFrameworkService, (JobHandler) bean);
|
||||
// // 有 TenantJob 注解的情况下,才会进行处理
|
||||
// if (!AnnotationUtil.hasAnnotation(bean.getClass(), TenantJob.class)) {
|
||||
// return bean;
|
||||
// }
|
||||
//
|
||||
// // 使用 TenantJobHandlerDecorator 装饰
|
||||
// return new TenantJobHandlerDecorator(tenantFrameworkService, (JobHandler) bean);
|
||||
return bean;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TenantJobAspect tenantJobAspect(TenantFrameworkService tenantFrameworkService) {
|
||||
return new TenantJobAspect(tenantFrameworkService);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
package cn.iocoder.yudao.framework.tenant.core.job;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.exceptions.ExceptionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
|
||||
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
||||
import com.xxl.job.core.context.XxlJobHelper;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Aspect
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class TenantJobAspect {
|
||||
|
||||
private final TenantFrameworkService tenantFrameworkService;
|
||||
|
||||
@Around("@annotation(xxlJob)")
|
||||
public Object around(ProceedingJoinPoint joinPoint, XxlJob xxlJob) throws Throwable {
|
||||
// 如果非多租户 Job,则跳过
|
||||
TenantJob tenantJob = getClassAnnotation(joinPoint, TenantJob.class);
|
||||
if (tenantJob == null) {
|
||||
return joinPoint.proceed();
|
||||
}
|
||||
|
||||
// 如果是多租户 Job,则会按照租户逐个执行 Job 的逻辑
|
||||
execute(joinPoint, xxlJob);
|
||||
return null; // JobHandler 无返回
|
||||
}
|
||||
|
||||
private void execute(ProceedingJoinPoint joinPoint, XxlJob xxlJob) {
|
||||
// 获得租户列表
|
||||
List<Long> tenantIds = tenantFrameworkService.getTenantIds();
|
||||
if (CollUtil.isEmpty(tenantIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 逐个租户,执行 Job
|
||||
Map<Long, String> results = new ConcurrentHashMap<>();
|
||||
tenantIds.parallelStream().forEach(tenantId -> { // TODO 芋艿:先通过 parallel 实现并行;1)多个租户,是一条执行日志;2)异常的情况
|
||||
TenantUtils.execute(tenantId, () -> {
|
||||
try {
|
||||
joinPoint.proceed();
|
||||
} catch (Throwable e) {
|
||||
results.put(tenantId, ExceptionUtil.getRootCauseMessage(e));
|
||||
// 打印异常
|
||||
XxlJobHelper.log(StrUtil.format("[多租户({}) 执行任务({}),发生异常:{}]",
|
||||
tenantId, xxlJob.value(), ExceptionUtils.getStackTrace(e)));
|
||||
}
|
||||
});
|
||||
});
|
||||
// 如果 results 非空,说明发生了异常,标记 XXL-Job 执行失败
|
||||
if (CollUtil.isNotEmpty(results)) {
|
||||
XxlJobHelper.handleFail(JsonUtils.toJsonString(results));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static <T extends Annotation> T getClassAnnotation(ProceedingJoinPoint joinPoint, Class<T> annotationClass) {
|
||||
return ((MethodSignature) joinPoint.getSignature()).getMethod().getDeclaringClass().getAnnotation(annotationClass);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package cn.iocoder.yudao.framework.tenant.core.job;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
|
||||
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 多租户 JobHandler 装饰器
|
||||
* 任务执行时,会按照租户逐个执行 Job 的逻辑
|
||||
*
|
||||
* 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public class TenantJobHandlerDecorator implements JobHandler {
|
||||
|
||||
private final TenantFrameworkService tenantFrameworkService;
|
||||
/**
|
||||
* 被装饰的 Job
|
||||
*/
|
||||
private final JobHandler jobHandler;
|
||||
|
||||
@Override
|
||||
public final String execute(String param) throws Exception {
|
||||
// 获得租户列表
|
||||
List<Long> tenantIds = tenantFrameworkService.getTenantIds();
|
||||
if (CollUtil.isEmpty(tenantIds)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 逐个租户,执行 Job
|
||||
Map<Long, String> results = new ConcurrentHashMap<>();
|
||||
tenantIds.parallelStream().forEach(tenantId -> { // TODO 芋艿:先通过 parallel 实现并行;1)多个租户,是一条执行日志;2)异常的情况
|
||||
try {
|
||||
// 设置租户
|
||||
TenantContextHolder.setTenantId(tenantId);
|
||||
// 执行 Job
|
||||
String result = jobHandler.execute(param);
|
||||
// 添加结果
|
||||
results.put(tenantId, result);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
TenantContextHolder.clear();
|
||||
}
|
||||
});
|
||||
return JsonUtils.toJsonString(results);
|
||||
}
|
||||
|
||||
}
|
|
@ -12,10 +12,7 @@
|
|||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>任务拓展
|
||||
1. 定时任务,基于 Quartz 拓展
|
||||
2. 异步任务,基于 Spring Async 拓展
|
||||
</description>
|
||||
<description>任务拓展,基于 XXL-Job 实现</description>
|
||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
<dependencies>
|
||||
|
@ -24,10 +21,22 @@
|
|||
<artifactId>yudao-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Job 定时任务相关 -->
|
||||
<!-- Spring 核心 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-quartz</artifactId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Job 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.xuxueli</groupId>
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
package cn.iocoder.yudao.framework.quartz.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* XXL-Job 配置类
|
||||
*/
|
||||
@ConfigurationProperties("xxl.job")
|
||||
@Validated
|
||||
@Data
|
||||
public class XxlJobProperties {
|
||||
|
||||
/**
|
||||
* 是否开启,默认为 true 关闭
|
||||
*/
|
||||
private Boolean enabled = true;
|
||||
/**
|
||||
* 访问令牌
|
||||
*/
|
||||
private String accessToken;
|
||||
/**
|
||||
* 控制器配置
|
||||
*/
|
||||
@NotNull(message = "控制器配置不能为空")
|
||||
private AdminProperties admin;
|
||||
/**
|
||||
* 执行器配置
|
||||
*/
|
||||
@NotNull(message = "执行器配置不能为空")
|
||||
private ExecutorProperties executor;
|
||||
|
||||
/**
|
||||
* XXL-Job 调度器配置类
|
||||
*/
|
||||
@Data
|
||||
@Valid
|
||||
public static class AdminProperties {
|
||||
|
||||
/**
|
||||
* 调度器地址
|
||||
*/
|
||||
@NotEmpty(message = "调度器地址不能为空")
|
||||
private String addresses;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* XXL-Job 执行器配置类
|
||||
*/
|
||||
@Data
|
||||
@Valid
|
||||
public static class ExecutorProperties {
|
||||
|
||||
/**
|
||||
* 默认端口
|
||||
*
|
||||
* 这里使用 -1 表示随机
|
||||
*/
|
||||
private static final Integer PORT_DEFAULT = -1;
|
||||
|
||||
/**
|
||||
* 默认日志保留天数
|
||||
*
|
||||
* 如果想永久保留,则设置为 -1
|
||||
*/
|
||||
private static final Integer LOG_RETENTION_DAYS_DEFAULT = 30;
|
||||
|
||||
/**
|
||||
* 应用名
|
||||
*/
|
||||
@NotEmpty(message = "应用名不能为空")
|
||||
private String appName;
|
||||
/**
|
||||
* 执行器的 IP
|
||||
*/
|
||||
private String ip;
|
||||
/**
|
||||
* 执行器的 Port
|
||||
*/
|
||||
private Integer port = PORT_DEFAULT;
|
||||
/**
|
||||
* 日志地址
|
||||
*/
|
||||
@NotEmpty(message = "日志地址不能为空")
|
||||
private String logPath;
|
||||
/**
|
||||
* 日志保留天数
|
||||
*/
|
||||
private Integer logRetentionDays = LOG_RETENTION_DAYS_DEFAULT;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package cn.iocoder.yudao.framework.quartz.config;
|
||||
|
||||
import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager;
|
||||
import org.quartz.Scheduler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* 定时任务 Configuration
|
||||
*/
|
||||
@Configuration
|
||||
@EnableScheduling // 开启 Spring 自带的定时任务
|
||||
public class YudaoQuartzAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public SchedulerManager schedulerManager(Scheduler scheduler) {
|
||||
return new SchedulerManager(scheduler);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,45 +1,35 @@
|
|||
package cn.iocoder.mall.xxljob.config;
|
||||
package cn.iocoder.yudao.framework.quartz.config;
|
||||
|
||||
import com.xxl.job.core.executor.XxlJobExecutor;
|
||||
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* XXL-Job 自动配置类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(XxlJobSpringExecutor.class)
|
||||
@ConditionalOnProperty(prefix = "xxl.job", name = "enabled", havingValue = "true", matchIfMissing = true)
|
||||
@EnableConfigurationProperties({XxlJobProperties.class})
|
||||
public class XxlJobAutoConfiguration {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(XxlJobAutoConfiguration.class);
|
||||
|
||||
private final XxlJobProperties properties;
|
||||
|
||||
public XxlJobAutoConfiguration(XxlJobProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
@EnableScheduling // 开启 Spring 自带的定时任务
|
||||
@Slf4j
|
||||
public class YudaoXxlJobAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public XxlJobExecutor xxlJobExecutor() {
|
||||
LOGGER.info("初始化 XXL-Job 执行器的配置");
|
||||
|
||||
// 参数校验
|
||||
XxlJobProperties.AdminProperties admin = this.properties.getAdmin();
|
||||
XxlJobProperties.ExecutorProperties executor = this.properties.getExecutor();
|
||||
Objects.requireNonNull(admin, "xxl job admin properties must not be null.");
|
||||
Objects.requireNonNull(executor, "xxl job executor properties must not be null.");
|
||||
public XxlJobExecutor xxlJobExecutor(XxlJobProperties properties) {
|
||||
log.info("[xxlJobExecutor][初始化 XXL-Job 执行器的配置]");
|
||||
XxlJobProperties.AdminProperties admin = properties.getAdmin();
|
||||
XxlJobProperties.ExecutorProperties executor = properties.getExecutor();
|
||||
|
||||
// 初始化执行器
|
||||
XxlJobExecutor xxlJobExecutor = new XxlJobSpringExecutor();
|
||||
|
@ -49,7 +39,7 @@ public class XxlJobAutoConfiguration {
|
|||
xxlJobExecutor.setLogPath(executor.getLogPath());
|
||||
xxlJobExecutor.setLogRetentionDays(executor.getLogRetentionDays());
|
||||
xxlJobExecutor.setAdminAddresses(admin.getAddresses());
|
||||
xxlJobExecutor.setAccessToken(this.properties.getAccessToken());
|
||||
xxlJobExecutor.setAccessToken(properties.getAccessToken());
|
||||
return xxlJobExecutor;
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package cn.iocoder.yudao.framework.quartz.core.enums;
|
||||
|
||||
/**
|
||||
* Quartz Job Data 的 key 枚举
|
||||
*/
|
||||
public enum JobDataKeyEnum {
|
||||
|
||||
JOB_ID,
|
||||
JOB_HANDLER_NAME,
|
||||
JOB_HANDLER_PARAM,
|
||||
JOB_RETRY_COUNT, // 最大重试次数
|
||||
JOB_RETRY_INTERVAL, // 每次重试间隔
|
||||
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package cn.iocoder.yudao.framework.quartz.core.handler;
|
||||
|
||||
/**
|
||||
* 任务处理器
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface JobHandler {
|
||||
|
||||
/**
|
||||
* 执行任务
|
||||
*
|
||||
* @param param 参数
|
||||
* @return 结果
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
String execute(String param) throws Exception;
|
||||
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
package cn.iocoder.yudao.framework.quartz.core.handler;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.iocoder.yudao.framework.quartz.core.enums.JobDataKeyEnum;
|
||||
import cn.iocoder.yudao.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.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.diff;
|
||||
|
||||
/**
|
||||
* 基础 Job 调用者,负责调用 {@link JobHandler#execute(String)} 执行任务
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@DisallowConcurrentExecution
|
||||
@PersistJobDataAfterExecution
|
||||
@Slf4j
|
||||
public class JobHandlerInvoker extends QuartzJobBean {
|
||||
|
||||
@Resource
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Resource
|
||||
private JobLogFrameworkService jobLogFrameworkService;
|
||||
|
||||
@Override
|
||||
protected void executeInternal(JobExecutionContext executionContext) throws JobExecutionException {
|
||||
// 第一步,获得 Job 数据
|
||||
Long jobId = executionContext.getMergedJobDataMap().getLong(JobDataKeyEnum.JOB_ID.name());
|
||||
String jobHandlerName = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_NAME.name());
|
||||
String jobHandlerParam = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_PARAM.name());
|
||||
int refireCount = executionContext.getRefireCount();
|
||||
int retryCount = (Integer) executionContext.getMergedJobDataMap().getOrDefault(JobDataKeyEnum.JOB_RETRY_COUNT.name(), 0);
|
||||
int retryInterval = (Integer) executionContext.getMergedJobDataMap().getOrDefault(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), 0);
|
||||
|
||||
// 第二步,执行任务
|
||||
Long jobLogId = null;
|
||||
Date startTime = new Date();
|
||||
String data = null;
|
||||
Throwable exception = null;
|
||||
try {
|
||||
// 记录 Job 日志(初始)
|
||||
jobLogId = jobLogFrameworkService.createJobLog(jobId, startTime, jobHandlerName, jobHandlerParam, refireCount + 1);
|
||||
// 执行任务
|
||||
data = this.executeInternal(jobHandlerName, jobHandlerParam);
|
||||
} catch (Throwable ex) {
|
||||
exception = ex;
|
||||
}
|
||||
|
||||
// 第三步,记录执行日志
|
||||
this.updateJobLogResultAsync(jobLogId, startTime, data, exception, executionContext);
|
||||
|
||||
// 第四步,处理有异常的情况
|
||||
handleException(exception, refireCount, retryCount, retryInterval);
|
||||
}
|
||||
|
||||
private String executeInternal(String jobHandlerName, String jobHandlerParam) throws Exception {
|
||||
// 获得 JobHandler 对象
|
||||
JobHandler jobHandler = applicationContext.getBean(jobHandlerName, JobHandler.class);
|
||||
Assert.notNull(jobHandler, "JobHandler 不会为空");
|
||||
// 执行任务
|
||||
return jobHandler.execute(jobHandlerParam);
|
||||
}
|
||||
|
||||
private void updateJobLogResultAsync(Long jobLogId, Date startTime, String data, Throwable exception,
|
||||
JobExecutionContext executionContext) {
|
||||
Date endTime = new Date();
|
||||
// 处理是否成功
|
||||
boolean success = exception == null;
|
||||
if (!success) {
|
||||
data = getRootCauseMessage(exception);
|
||||
}
|
||||
// 更新日志
|
||||
try {
|
||||
jobLogFrameworkService.updateJobLogResultAsync(jobLogId, endTime, (int) diff(endTime, startTime), success, data);
|
||||
} catch (Exception ex) {
|
||||
log.error("[executeInternal][Job({}) logId({}) 记录执行日志失败({}/{})]",
|
||||
executionContext.getJobDetail().getKey(), jobLogId, success, data);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleException(Throwable exception,
|
||||
int refireCount, int retryCount, int retryInterval) throws JobExecutionException {
|
||||
// 如果有异常,则进行重试
|
||||
if (exception == null) {
|
||||
return;
|
||||
}
|
||||
// 情况一:如果到达重试上限,则直接抛出异常即可
|
||||
if (refireCount >= retryCount) {
|
||||
throw new JobExecutionException(exception);
|
||||
}
|
||||
|
||||
// 情况二:如果未到达重试上限,则 sleep 一定间隔时间,然后重试
|
||||
// 这里使用 sleep 来实现,主要还是希望实现比较简单。因为,同一时间,不会存在大量失败的 Job。
|
||||
if (retryInterval > 0) {
|
||||
ThreadUtil.sleep(retryInterval);
|
||||
}
|
||||
// 第二个参数,refireImmediately = true,表示立即重试
|
||||
throw new JobExecutionException(exception, true);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
package cn.iocoder.yudao.framework.quartz.core.scheduler;
|
||||
|
||||
import cn.iocoder.yudao.framework.quartz.core.enums.JobDataKeyEnum;
|
||||
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker;
|
||||
import org.quartz.*;
|
||||
|
||||
/**
|
||||
* {@link org.quartz.Scheduler} 的管理器,负责创建任务
|
||||
*
|
||||
* 考虑到实现的简洁性,我们使用 jobHandlerName 作为唯一标识,即:
|
||||
* 1. Job 的 {@link JobDetail#getKey()}
|
||||
* 2. Trigger 的 {@link Trigger#getKey()}
|
||||
*
|
||||
* 另外,jobHandlerName 对应到 Spring Bean 的名字,直接调用
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class SchedulerManager {
|
||||
|
||||
private final Scheduler scheduler;
|
||||
|
||||
public SchedulerManager(Scheduler scheduler) {
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 Job 到 Quartz 中
|
||||
*
|
||||
* @param jobId 任务编号
|
||||
* @param jobHandlerName 任务处理器的名字
|
||||
* @param jobHandlerParam 任务处理器的参数
|
||||
* @param cronExpression CRON 表达式
|
||||
* @param retryCount 重试次数
|
||||
* @param retryInterval 重试间隔
|
||||
* @throws SchedulerException 添加异常
|
||||
*/
|
||||
public void addJob(Long jobId, String jobHandlerName, String jobHandlerParam, String cronExpression,
|
||||
Integer retryCount, Integer retryInterval)
|
||||
throws SchedulerException {
|
||||
// 创建 JobDetail 对象
|
||||
JobDetail jobDetail = JobBuilder.newJob(JobHandlerInvoker.class)
|
||||
.usingJobData(JobDataKeyEnum.JOB_ID.name(), jobId)
|
||||
.usingJobData(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName)
|
||||
.withIdentity(jobHandlerName).build();
|
||||
// 创建 Trigger 对象
|
||||
Trigger trigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval);
|
||||
// 新增调度
|
||||
scheduler.scheduleJob(jobDetail, trigger);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新 Job 到 Quartz
|
||||
*
|
||||
* @param jobHandlerName 任务处理器的名字
|
||||
* @param jobHandlerParam 任务处理器的参数
|
||||
* @param cronExpression CRON 表达式
|
||||
* @param retryCount 重试次数
|
||||
* @param retryInterval 重试间隔
|
||||
* @throws SchedulerException 更新异常
|
||||
*/
|
||||
public void updateJob(String jobHandlerName, String jobHandlerParam, String cronExpression,
|
||||
Integer retryCount, Integer retryInterval)
|
||||
throws SchedulerException {
|
||||
// 创建新 Trigger 对象
|
||||
Trigger newTrigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval);
|
||||
// 修改调度
|
||||
scheduler.rescheduleJob(new TriggerKey(jobHandlerName), newTrigger);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 Quartz 中的 Job
|
||||
*
|
||||
* @param jobHandlerName 任务处理器的名字
|
||||
* @throws SchedulerException 删除异常
|
||||
*/
|
||||
public void deleteJob(String jobHandlerName) throws SchedulerException {
|
||||
scheduler.deleteJob(new JobKey(jobHandlerName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停 Quartz 中的 Job
|
||||
*
|
||||
* @param jobHandlerName 任务处理器的名字
|
||||
* @throws SchedulerException 暂停异常
|
||||
*/
|
||||
public void pauseJob(String jobHandlerName) throws SchedulerException {
|
||||
scheduler.pauseJob(new JobKey(jobHandlerName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动 Quartz 中的 Job
|
||||
*
|
||||
* @param jobHandlerName 任务处理器的名字
|
||||
* @throws SchedulerException 启动异常
|
||||
*/
|
||||
public void resumeJob(String jobHandlerName) throws SchedulerException {
|
||||
scheduler.resumeJob(new JobKey(jobHandlerName));
|
||||
scheduler.resumeTrigger(new TriggerKey(jobHandlerName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即触发一次 Quartz 中的 Job
|
||||
*
|
||||
* @param jobId 任务编号
|
||||
* @param jobHandlerName 任务处理器的名字
|
||||
* @param jobHandlerParam 任务处理器的参数
|
||||
* @throws SchedulerException 触发异常
|
||||
*/
|
||||
public void triggerJob(Long jobId, String jobHandlerName, String jobHandlerParam)
|
||||
throws SchedulerException {
|
||||
JobDataMap data = new JobDataMap(); // 无需重试,所以不设置 retryCount 和 retryInterval
|
||||
data.put(JobDataKeyEnum.JOB_ID.name(), jobId);
|
||||
data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName);
|
||||
data.put(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam);
|
||||
// 触发任务
|
||||
scheduler.triggerJob(new JobKey(jobHandlerName), data);
|
||||
}
|
||||
|
||||
private Trigger buildTrigger(String jobHandlerName, String jobHandlerParam, String cronExpression,
|
||||
Integer retryCount, Integer retryInterval) {
|
||||
return TriggerBuilder.newTrigger()
|
||||
.withIdentity(jobHandlerName)
|
||||
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
|
||||
.usingJobData(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam)
|
||||
.usingJobData(JobDataKeyEnum.JOB_RETRY_COUNT.name(), retryCount)
|
||||
.usingJobData(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), retryInterval)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package cn.iocoder.yudao.framework.quartz.core.service;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Job 日志 Framework Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface JobLogFrameworkService {
|
||||
|
||||
/**
|
||||
* 创建 Job 日志
|
||||
*
|
||||
* @param jobId 任务编号
|
||||
* @param beginTime 开始时间
|
||||
* @param jobHandlerName Job 处理器的名字
|
||||
* @param jobHandlerParam Job 处理器的参数
|
||||
* @param executeIndex 第几次执行
|
||||
* @return Job 日志的编号
|
||||
*/
|
||||
Long createJobLog(@NotNull(message = "任务编号不能为空") Long jobId,
|
||||
@NotNull(message = "开始时间") Date beginTime,
|
||||
@NotEmpty(message = "Job 处理器的名字不能为空") String jobHandlerName,
|
||||
String jobHandlerParam,
|
||||
@NotNull(message = "第几次执行不能为空") Integer executeIndex);
|
||||
|
||||
/**
|
||||
* 更新 Job 日志的执行结果
|
||||
*
|
||||
* @param logId 日志编号
|
||||
* @param endTime 结束时间。因为是异步,避免记录时间不准去
|
||||
* @param duration 运行时长,单位:毫秒
|
||||
* @param success 是否成功
|
||||
* @param result 成功数据
|
||||
*/
|
||||
void updateJobLogResultAsync(@NotNull(message = "日志编号不能为空") Long logId,
|
||||
@NotNull(message = "结束时间不能为空") Date endTime,
|
||||
@NotNull(message = "运行时长不能为空") Integer duration,
|
||||
boolean success, String result);
|
||||
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
package cn.iocoder.yudao.framework.quartz.core.util;
|
||||
|
||||
import org.quartz.CronExpression;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Quartz Cron 表达式的工具类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class CronUtils {
|
||||
|
||||
/**
|
||||
* 校验 CRON 表达式是否有效
|
||||
*
|
||||
* @param cronExpression CRON 表达式
|
||||
* @return 是否有效
|
||||
*/
|
||||
public static boolean isValid(String cronExpression) {
|
||||
return CronExpression.isValidExpression(cronExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于 CRON 表达式,获得下 n 个满足执行的时间
|
||||
*
|
||||
* @param cronExpression CRON 表达式
|
||||
* @param n 数量
|
||||
* @return 满足条件的执行时间
|
||||
*/
|
||||
public static List<Date> getNextTimes(String cronExpression, int n) {
|
||||
// 获得 CronExpression 对象
|
||||
CronExpression cron;
|
||||
try {
|
||||
cron = new CronExpression(cronExpression);
|
||||
} catch (ParseException e) {
|
||||
throw new IllegalArgumentException(e.getMessage());
|
||||
}
|
||||
// 从当前开始计算,n 个满足条件的
|
||||
Date now = new Date();
|
||||
List<Date> nextTimes = new ArrayList<>(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
Date nextTime = cron.getNextValidTimeAfter(now);
|
||||
nextTimes.add(nextTime);
|
||||
// 切换现在,为下一个触发时间;
|
||||
now = nextTime;
|
||||
}
|
||||
return nextTimes;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
/**
|
||||
* 1. 定时任务,采用 Quartz 实现进程内的任务执行。
|
||||
* 考虑到高可用,使用 Quartz 自带的 MySQL 集群方案。
|
||||
*
|
||||
* 1. 定时任务,基于 XXL-Job 实现。
|
||||
* 2. 异步任务,采用 Spring Async 异步执行。
|
||||
*/
|
||||
package cn.iocoder.yudao.framework.quartz;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.iocoder.yudao.framework.quartz.config.YudaoQuartzAutoConfiguration,\
|
||||
cn.iocoder.yudao.framework.quartz.config.YudaoXxlJobAutoConfiguration,\
|
||||
cn.iocoder.yudao.framework.quartz.config.YudaoAsyncAutoConfiguration
|
||||
|
|
|
@ -94,11 +94,11 @@
|
|||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Job 定时任务相关 TODO 芋艿:暂时去掉 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.cloud</groupId>-->
|
||||
<!-- <artifactId>yudao-spring-boot-starter-job</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- Job 定时任务相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-job</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 消息队列相关 -->
|
||||
<dependency>
|
||||
|
|
|
@ -72,8 +72,10 @@ spring:
|
|||
name-server: 127.0.0.1:9876 # RocketMQ Namesrv 地址
|
||||
|
||||
--- #################### 定时任务相关配置 ####################
|
||||
|
||||
--- #################### 配置中心相关配置 ####################
|
||||
xxl:
|
||||
job:
|
||||
admin:
|
||||
addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址
|
||||
|
||||
--- #################### 服务保障相关配置 ####################
|
||||
|
||||
|
|
|
@ -83,8 +83,10 @@ spring:
|
|||
name-server: 127.0.0.1:9876 # RocketMQ Namesrv 地址
|
||||
|
||||
--- #################### 定时任务相关配置 ####################
|
||||
|
||||
--- #################### 配置中心相关配置 ####################
|
||||
xxl:
|
||||
job:
|
||||
admin:
|
||||
addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址
|
||||
|
||||
--- #################### 服务保障相关配置 ####################
|
||||
|
||||
|
|
|
@ -84,6 +84,15 @@ spring:
|
|||
id: ${spring.application.name}:${server.port} # 编号,Spring Cloud Alibaba 建议使用“应用:端口”的格式
|
||||
destination: springCloudBus # 目标消息队列,默认为 springCloudBus
|
||||
|
||||
--- #################### 定时任务相关配置 ####################
|
||||
|
||||
xxl:
|
||||
job:
|
||||
executor:
|
||||
appname: ${spring.application.name} # 执行器 AppName
|
||||
logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径
|
||||
accessToken: default_token # 执行器通讯TOKEN
|
||||
|
||||
--- #################### 芋道相关配置 ####################
|
||||
|
||||
yudao:
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package cn.iocoder.yudao.module.system.job.demo;
|
||||
|
||||
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@TenantJob
|
||||
public class DemoJob {
|
||||
|
||||
@XxlJob("demoJob")
|
||||
public void execute() {
|
||||
System.out.println("美滋滋");
|
||||
}
|
||||
|
||||
}
|
|
@ -72,6 +72,10 @@ spring:
|
|||
name-server: 127.0.0.1:9876 # RocketMQ Namesrv 地址
|
||||
|
||||
--- #################### 定时任务相关配置 ####################
|
||||
xxl:
|
||||
job:
|
||||
admin:
|
||||
addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址
|
||||
|
||||
--- #################### 服务保障相关配置 ####################
|
||||
|
||||
|
|
|
@ -83,6 +83,11 @@ spring:
|
|||
|
||||
--- #################### 定时任务相关配置 ####################
|
||||
|
||||
xxl:
|
||||
job:
|
||||
admin:
|
||||
addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址
|
||||
|
||||
--- #################### 服务保障相关配置 ####################
|
||||
|
||||
# Lock4j 配置项
|
||||
|
|
|
@ -82,6 +82,15 @@ spring:
|
|||
id: ${spring.application.name}:${server.port} # 编号,Spring Cloud Alibaba 建议使用“应用:端口”的格式
|
||||
destination: springCloudBus # 目标消息队列,默认为 springCloudBus
|
||||
|
||||
--- #################### 定时任务相关配置 ####################
|
||||
|
||||
xxl:
|
||||
job:
|
||||
executor:
|
||||
appname: ${spring.application.name} # 执行器 AppName
|
||||
logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径
|
||||
accessToken: default_token # 执行器通讯TOKEN
|
||||
|
||||
--- #################### 芋道相关配置 ####################
|
||||
|
||||
yudao:
|
||||
|
@ -110,6 +119,7 @@ yudao:
|
|||
- /admin-api/system/captcha/get-image # 获取图片验证码,和租户无关
|
||||
- /admin-api/system/sms/callback/* # 短信回调接口,无法带上租户编号
|
||||
- /rpc-api/system/tenant/valid # 防止递归。避免调用 /rpc-api/system/tenant/valid 接口时,又去触发 /rpc-api/system/tenant/valid 去校验
|
||||
- /rpc-api/system/tenant/id-list # 获得租户列表的时候,无需传递租户编号
|
||||
- /rpc-api/system/error-code/* # 错误码的自动创建与下载的接口,无法带上租户编号
|
||||
ignore-tables:
|
||||
- system_tenant
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>common</artifactId>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>mall-spring-boot-starter-xxl-job</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring 核心 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Job 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.xuxueli</groupId>
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -1,172 +0,0 @@
|
|||
package cn.iocoder.mall.xxljob.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* XXL-Job 配置类
|
||||
*/
|
||||
@ConfigurationProperties("xxl.job")
|
||||
public class XxlJobProperties {
|
||||
|
||||
/**
|
||||
* 是否开启,默认为 true 关闭
|
||||
*/
|
||||
private Boolean enabled = true;
|
||||
/**
|
||||
* 访问令牌
|
||||
*/
|
||||
private String accessToken;
|
||||
/**
|
||||
* 控制器配置
|
||||
*/
|
||||
private AdminProperties admin;
|
||||
/**
|
||||
* 执行器配置
|
||||
*/
|
||||
private ExecutorProperties executor;
|
||||
|
||||
public Boolean getEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled) {
|
||||
if (enabled != null) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void setAccessToken(String accessToken) {
|
||||
if (accessToken != null && accessToken.trim().length() > 0) {
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
}
|
||||
|
||||
public AdminProperties getAdmin() {
|
||||
return admin;
|
||||
}
|
||||
|
||||
public void setAdmin(AdminProperties admin) {
|
||||
this.admin = admin;
|
||||
}
|
||||
|
||||
public ExecutorProperties getExecutor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
public void setExecutor(ExecutorProperties executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* XXL-Job 调度器配置类
|
||||
*/
|
||||
public static class AdminProperties {
|
||||
|
||||
/**
|
||||
* 调度器地址
|
||||
*/
|
||||
private String addresses;
|
||||
|
||||
public String getAddresses() {
|
||||
return addresses;
|
||||
}
|
||||
|
||||
public void setAddresses(String addresses) {
|
||||
this.addresses = addresses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AdminProperties{" +
|
||||
"addresses='" + addresses + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* XXL-Job 执行器配置类
|
||||
*/
|
||||
public static class ExecutorProperties {
|
||||
|
||||
/**
|
||||
* 默认端口
|
||||
*
|
||||
* 这里使用 -1 表示随机
|
||||
*/
|
||||
private static final Integer PORT_DEFAULT = -1;
|
||||
|
||||
/**
|
||||
* 默认日志保留天数
|
||||
*
|
||||
* 默认为 -1,不清理,永久保留
|
||||
*/
|
||||
private static final Integer LOG_RETENTION_DAYS_DEFAULT = -1;
|
||||
|
||||
/**
|
||||
* 应用名
|
||||
*/
|
||||
private String appName;
|
||||
/**
|
||||
* 执行器的 IP
|
||||
*/
|
||||
private String ip;
|
||||
/**
|
||||
* 执行器的 Port
|
||||
*/
|
||||
private Integer port = PORT_DEFAULT;
|
||||
/**
|
||||
* 日志地址
|
||||
*/
|
||||
private String logPath;
|
||||
/**
|
||||
* 日志保留天数
|
||||
*/
|
||||
private Integer logRetentionDays = LOG_RETENTION_DAYS_DEFAULT;
|
||||
|
||||
public String getAppName() {
|
||||
return appName;
|
||||
}
|
||||
|
||||
public void setAppName(String appName) {
|
||||
this.appName = appName;
|
||||
}
|
||||
|
||||
public String getLogPath() {
|
||||
return logPath;
|
||||
}
|
||||
|
||||
public void setLogPath(String logPath) {
|
||||
this.logPath = logPath;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public Integer getLogRetentionDays() {
|
||||
return logRetentionDays;
|
||||
}
|
||||
|
||||
public void setLogRetentionDays(Integer logRetentionDays) {
|
||||
this.logRetentionDays = logRetentionDays;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.iocoder.mall.xxljob.config.XxlJobAutoConfiguration
|
Loading…
Reference in New Issue