解决定时任务集群问题

This commit is contained in:
chenjianxing 2020-06-28 20:43:43 +08:00
parent 0ed718c214
commit 94dbd9ca17
11 changed files with 377 additions and 105 deletions

View File

@ -162,9 +162,15 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.quartz-scheduler</groupId> <groupId>com.fit2cloud</groupId>
<artifactId>quartz</artifactId> <artifactId>quartz-spring-boot-starter</artifactId>
<version>2.3.0</version> <exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</exclusion>
</exclusions>
<version>0.0.4</version>
</dependency> </dependency>
<!-- LDAP Module --> <!-- LDAP Module -->
@ -288,5 +294,43 @@
</plugins> </plugins>
</build> </build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/libs-milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>jcenter-snapshots</id>
<name>jcenter</name>
<url>https://jcenter.bintray.com/</url>
</repository>
<repository>
<id>fit2cloud-enterprise-release</id>
<name>Fit2Cloud Enterprise Release</name>
<url>http://repository.fit2cloud.com/content/repositories/fit2cloud-enterprise-release/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>fit2cloud</id>
<name>fit2cloud</name>
<url>http://repository.fit2cloud.com/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project> </project>

View File

@ -8,6 +8,7 @@ import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.PropertySource; import org.springframework.context.annotation.PropertySource;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication(exclude = {QuartzAutoConfiguration.class}) @SpringBootApplication(exclude = {QuartzAutoConfiguration.class})
@ServletComponentScan @ServletComponentScan
@ -15,6 +16,7 @@ import org.springframework.context.annotation.PropertySource;
KafkaProperties.class, KafkaProperties.class,
JmeterProperties.class JmeterProperties.class
}) })
@EnableScheduling
@PropertySource(value = {"file:/opt/metersphere/conf/metersphere.properties"}, encoding = "UTF-8", ignoreResourceNotFound = true) @PropertySource(value = {"file:/opt/metersphere/conf/metersphere.properties"}, encoding = "UTF-8", ignoreResourceNotFound = true)
public class Application { public class Application {
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -14,35 +14,24 @@ import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.constants.ScheduleType; import io.metersphere.commons.constants.ScheduleType;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.BeanUtils; import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils; import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import io.metersphere.job.QuartzManager;
import io.metersphere.job.sechedule.ApiTestJob; import io.metersphere.job.sechedule.ApiTestJob;
import io.metersphere.job.sechedule.PerformanceTestJob;
import io.metersphere.service.FileService; import io.metersphere.service.FileService;
import io.metersphere.service.ScheduleService; import io.metersphere.service.ScheduleService;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.SchedulerException;
import org.quartz.TriggerKey;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Random; import java.util.Random;
import java.util.UUID; import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service

View File

@ -0,0 +1,93 @@
package io.metersphere.config;
import com.fit2cloud.autoconfigure.QuartzProperties;
import com.fit2cloud.quartz.QuartzInstanceIdGenerator;
import com.fit2cloud.quartz.SchedulerStarter;
import com.fit2cloud.quartz.service.QuartzManageService;
import com.fit2cloud.quartz.util.QuartzBeanFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
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 org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.util.StringUtils;
import javax.sql.DataSource;
import java.util.Properties;
import java.util.TimeZone;
@Configuration
@EnableConfigurationProperties(QuartzProperties.class)
@ConditionalOnClass(DataSource.class)
@AutoConfigureAfter(DataSource.class)
public class QuartzAutoConfiguration {
private DataSource dataSource;
private QuartzProperties properties;
public QuartzAutoConfiguration(ObjectProvider<DataSource> dataSourceProvider, QuartzProperties properties) {
this.dataSource = dataSourceProvider.getIfAvailable();
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true")
public SchedulerStarter schedulerStarter() {
return new SchedulerStarter();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true")
public QuartzBeanFactory quartzBeanFactory() {
return new QuartzBeanFactory();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true")
public QuartzManageService quartzManageService() {
return new QuartzManageService();
}
@Bean
@ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true")
public TimeZone quartzTimeZone() {
return TimeZone.getTimeZone(properties.getTimeZone());
}
@Bean
@ConditionalOnClass(DataSource.class)
@ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true")
public SchedulerFactoryBean clusterSchedulerFactoryBean() {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
schedulerFactoryBean.setDataSource(this.dataSource);
schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContextKey");
schedulerFactoryBean.setOverwriteExistingJobs(true);
schedulerFactoryBean.setStartupDelay(60);// 60 秒之后开始执行定时任务
Properties props = new Properties();
props.put("org.quartz.scheduler.instanceName", "clusterScheduler");
props.put("org.quartz.scheduler.instanceId", "AUTO"); // 集群下的instanceId 必须唯一
props.put("org.quartz.scheduler.instanceIdGenerator.class", QuartzInstanceIdGenerator.class.getName());// instanceId 生成的方式
props.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
props.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.StdJDBCDelegate");
props.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
props.put("org.quartz.jobStore.isClustered", "true");
props.put("org.quartz.jobStore.clusterCheckinInterval", "20000");
props.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
props.put("org.quartz.threadPool.threadCount", "10");
props.put("org.quartz.threadPool.threadPriority", "5");
props.put("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread", "true");
schedulerFactoryBean.setQuartzProperties(props);
if (!StringUtils.isEmpty(this.properties.getSchedulerName())) {
schedulerFactoryBean.setBeanName(this.properties.getSchedulerName());
}
return schedulerFactoryBean;
}
}

View File

@ -5,10 +5,10 @@ import io.metersphere.api.service.APITestService;
import io.metersphere.commons.constants.ReportTriggerMode; import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.constants.ScheduleGroup; import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil; import org.quartz.JobExecutionContext;
import io.metersphere.job.QuartzManager; import org.quartz.JobKey;
import org.apache.commons.lang3.StringUtils; import org.quartz.TriggerKey;
import org.quartz.*;
public class ApiTestJob extends MsScheduleJob { public class ApiTestJob extends MsScheduleJob {
@ -19,12 +19,7 @@ public class ApiTestJob extends MsScheduleJob {
} }
@Override @Override
public void execute(JobExecutionContext context) throws JobExecutionException { void businessExecute(JobExecutionContext context) {
if (StringUtils.isBlank(resourceId)) {
QuartzManager.removeJob(getJobKey(resourceId), getTriggerKey(resourceId));
}
LogUtil.info("ApiTestSchedule Running: " + resourceId);
LogUtil.info("CronExpression: " + expression);
SaveAPITestRequest request = new SaveAPITestRequest(); SaveAPITestRequest request = new SaveAPITestRequest();
request.setId(resourceId); request.setId(resourceId);
request.setUserId(userId); request.setUserId(userId);

View File

@ -1,8 +1,9 @@
package io.metersphere.job.sechedule; package io.metersphere.job.sechedule;
import org.quartz.Job; import io.metersphere.commons.utils.LogUtil;
import org.quartz.*;
public abstract class MsScheduleJob implements Job{ public abstract class MsScheduleJob implements Job {
protected String resourceId; protected String resourceId;
@ -10,15 +11,19 @@ public abstract class MsScheduleJob implements Job{
protected String expression; protected String expression;
public void setResourceId(String resourceId) { @Override
this.resourceId = resourceId; public void execute(JobExecutionContext context) throws JobExecutionException {
JobKey jobKey = context.getTrigger().getJobKey();
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
this.resourceId = jobDataMap.getString("resourceId");
this.userId = jobDataMap.getString("userId");
this.expression = jobDataMap.getString("expression");
LogUtil.info(jobKey.getGroup()+ " Running: " + resourceId);
LogUtil.info("CronExpression: " + expression);
businessExecute(context);
} }
public void setExpression(String expression) { abstract void businessExecute(JobExecutionContext context);
this.expression = expression;
}
public void setUserId(String userId) {
this.userId = userId;
}
} }

View File

@ -3,13 +3,9 @@ package io.metersphere.job.sechedule;
import io.metersphere.commons.constants.ReportTriggerMode; import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.constants.ScheduleGroup; import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.job.QuartzManager;
import io.metersphere.performance.service.PerformanceTestService; import io.metersphere.performance.service.PerformanceTestService;
import io.metersphere.track.request.testplan.RunTestPlanRequest; import io.metersphere.track.request.testplan.RunTestPlanRequest;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey; import org.quartz.JobKey;
import org.quartz.TriggerKey; import org.quartz.TriggerKey;
@ -22,18 +18,12 @@ public class PerformanceTestJob extends MsScheduleJob {
} }
@Override @Override
public void execute(JobExecutionContext context) throws JobExecutionException { void businessExecute(JobExecutionContext context) {
if (StringUtils.isBlank(resourceId)) {
QuartzManager.removeJob(getJobKey(resourceId), getTriggerKey(resourceId));
}
LogUtil.info("PerformanceTestSchedule Running: " + resourceId);
LogUtil.info("CronExpression: " + expression);
RunTestPlanRequest request = new RunTestPlanRequest(); RunTestPlanRequest request = new RunTestPlanRequest();
request.setId(resourceId); request.setId(resourceId);
request.setUserId(userId); request.setUserId(userId);
request.setTriggerMode(ReportTriggerMode.SCHEDULE.name()); request.setTriggerMode(ReportTriggerMode.SCHEDULE.name());
performanceTestService.run(request); performanceTestService.run(request);
} }
public static JobKey getJobKey(String testId) { public static JobKey getJobKey(String testId) {

View File

@ -1,12 +1,16 @@
package io.metersphere.job; package io.metersphere.job.sechedule;
import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.LogUtil;
import org.quartz.*; import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory; import org.springframework.stereotype.Component;
public class QuartzManager { import javax.annotation.Resource;
public static StdSchedulerFactory sf = new StdSchedulerFactory(); @Component
public class ScheduleManager {
@Resource
private Scheduler scheduler;
/** /**
* 添加 simpleJob * 添加 simpleJob
@ -17,24 +21,28 @@ public class QuartzManager {
* @param jobDataMap * @param jobDataMap
* @throws SchedulerException * @throws SchedulerException
*/ */
public static void addSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class<? extends Job> cls, int repeatIntervalTime, public void addSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class<? extends Job> cls, int repeatIntervalTime,
JobDataMap jobDataMap) throws SchedulerException { JobDataMap jobDataMap) throws SchedulerException {
Scheduler sched = sf.getScheduler(); JobBuilder jobBuilder = JobBuilder.newJob(cls).withIdentity(jobKey);
JobDetail jd = JobBuilder.newJob(cls).withIdentity(jobKey).setJobData(jobDataMap).build(); if (jobDataMap != null) {
jobBuilder.usingJobData(jobDataMap);
}
JobDetail jd = jobBuilder.build();
SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey) SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
.withSchedule( .withSchedule(
SimpleScheduleBuilder.simpleSchedule().withIntervalInHours(repeatIntervalTime).repeatForever()) SimpleScheduleBuilder.simpleSchedule().withIntervalInHours(repeatIntervalTime).repeatForever())
.startNow().build(); .startNow().build();
sched.scheduleJob(jd, trigger); scheduler.scheduleJob(jd, trigger);
try { try {
if (!sched.isShutdown()) { if (!scheduler.isShutdown()) {
sched.start(); scheduler.start();
} }
} catch (SchedulerException e) { } catch (SchedulerException e) {
@ -44,8 +52,8 @@ public class QuartzManager {
} }
} }
public static void addSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class<? extends Job> cls, int repeatIntervalTime) throws SchedulerException { public void addSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class<? extends Job> cls, int repeatIntervalTime) throws SchedulerException {
addSimpleJob(jobKey, triggerKey, cls, repeatIntervalTime); addSimpleJob(jobKey, triggerKey, cls, repeatIntervalTime);
} }
/** /**
@ -56,11 +64,14 @@ public class QuartzManager {
* @param cron * @param cron
* @param jobDataMap * @param jobDataMap
*/ */
public static void addCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, JobDataMap jobDataMap) { public void addCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, JobDataMap jobDataMap) {
try { try {
LogUtil.info("addCronJob: " + triggerKey.getName() + "," + triggerKey.getGroup());
JobBuilder jobBuilder = JobBuilder.newJob(jobClass).withIdentity(jobKey); JobBuilder jobBuilder = JobBuilder.newJob(jobClass).withIdentity(jobKey);
if (jobDataMap != null) { if (jobDataMap != null) {
jobBuilder.setJobData(jobDataMap); jobBuilder.usingJobData(jobDataMap);
} }
JobDetail jobDetail = jobBuilder.build(); JobDetail jobDetail = jobBuilder.build();
@ -74,12 +85,10 @@ public class QuartzManager {
CronTrigger trigger = (CronTrigger) triggerBuilder.build(); CronTrigger trigger = (CronTrigger) triggerBuilder.build();
Scheduler sched = sf.getScheduler(); scheduler.scheduleJob(jobDetail, trigger);
sched.scheduleJob(jobDetail, trigger); if (!scheduler.isShutdown()) {
scheduler.start();
if (!sched.isShutdown()) {
sched.start();
} }
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e.getMessage(), e); LogUtil.error(e.getMessage(), e);
@ -87,7 +96,7 @@ public class QuartzManager {
} }
} }
public static void addCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron) { public void addCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron) {
addCronJob(jobKey, triggerKey, jobClass, cron, null); addCronJob(jobKey, triggerKey, jobClass, cron, null);
} }
@ -97,14 +106,12 @@ public class QuartzManager {
* @param cron * @param cron
* @throws SchedulerException * @throws SchedulerException
*/ */
public static void modifyCronJobTime(TriggerKey triggerKey, String cron) throws SchedulerException { public void modifyCronJobTime(TriggerKey triggerKey, String cron) throws SchedulerException {
Scheduler sched = sf.getScheduler();
LogUtil.info("modifyCronJobTime: " + triggerKey.getName() + "," + triggerKey.getGroup()); LogUtil.info("modifyCronJobTime: " + triggerKey.getName() + "," + triggerKey.getGroup());
try { try {
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey); CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (trigger == null) { if (trigger == null) {
return; return;
@ -125,7 +132,7 @@ public class QuartzManager {
trigger = (CronTrigger) triggerBuilder.build();// 创建Trigger对象 trigger = (CronTrigger) triggerBuilder.build();// 创建Trigger对象
sched.rescheduleJob(triggerKey, trigger);// 修改一个任务的触发时间 scheduler.rescheduleJob(triggerKey, trigger);// 修改一个任务的触发时间
/** 方式一 :调用 rescheduleJob 结束 */ /** 方式一 :调用 rescheduleJob 结束 */
/** 方式二先删除然后在创建一个新的Job */ /** 方式二先删除然后在创建一个新的Job */
@ -146,15 +153,13 @@ public class QuartzManager {
* @param repeatIntervalTime * @param repeatIntervalTime
* @throws SchedulerException * @throws SchedulerException
*/ */
public static void modifySimpleJobTime(TriggerKey triggerKey, int repeatIntervalTime) throws SchedulerException { public void modifySimpleJobTime(TriggerKey triggerKey, int repeatIntervalTime) throws SchedulerException {
Scheduler sched = sf.getScheduler();
try { try {
LogUtil.info("modifySimpleJobTime: " + triggerKey.getName() + "," + triggerKey.getGroup()); LogUtil.info("modifySimpleJobTime: " + triggerKey.getName() + "," + triggerKey.getGroup());
SimpleTrigger trigger = (SimpleTrigger) sched.getTrigger(triggerKey); SimpleTrigger trigger = (SimpleTrigger) scheduler.getTrigger(triggerKey);
if (trigger == null) { if (trigger == null) {
return; return;
@ -175,7 +180,7 @@ public class QuartzManager {
trigger = (SimpleTrigger) triggerBuilder.build();// 创建Trigger对象 trigger = (SimpleTrigger) triggerBuilder.build();// 创建Trigger对象
sched.rescheduleJob(triggerKey, trigger);// 修改一个任务的触发时间 scheduler.rescheduleJob(triggerKey, trigger);// 修改一个任务的触发时间
/** 方式一 :调用 rescheduleJob 结束 */ /** 方式一 :调用 rescheduleJob 结束 */
@ -201,19 +206,17 @@ public class QuartzManager {
* @param jobKey * @param jobKey
* @param triggerKey * @param triggerKey
*/ */
public static void removeJob(JobKey jobKey, TriggerKey triggerKey) { public void removeJob(JobKey jobKey, TriggerKey triggerKey) {
try { try {
LogUtil.info("RemoveJob: " + jobKey.getName() + "," + jobKey.getGroup()); LogUtil.info("RemoveJob: " + jobKey.getName() + "," + jobKey.getGroup());
Scheduler sched = sf.getScheduler(); scheduler.pauseTrigger(triggerKey);
sched.pauseTrigger(triggerKey); scheduler.unscheduleJob(triggerKey);
sched.unscheduleJob(triggerKey); scheduler.deleteJob(jobKey);
sched.deleteJob(jobKey);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e.getMessage(), e); LogUtil.error(e.getMessage(), e);
@ -232,7 +235,7 @@ public class QuartzManager {
} }
public static void shutdownJobs(Scheduler sched) { public void shutdownJobs(Scheduler sched) {
try { try {
if (!sched.isShutdown()) { if (!sched.isShutdown()) {
sched.shutdown(); sched.shutdown();
@ -252,12 +255,10 @@ public class QuartzManager {
* @param jobDataMap * @param jobDataMap
* @throws SchedulerException * @throws SchedulerException
*/ */
public static void addOrUpdateSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class clz, public void addOrUpdateSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class clz,
int intervalTime, JobDataMap jobDataMap) throws SchedulerException { int intervalTime, JobDataMap jobDataMap) throws SchedulerException {
Scheduler sched = sf.getScheduler(); if (scheduler.checkExists(triggerKey)) {
if (sched.checkExists(triggerKey)) {
modifySimpleJobTime(triggerKey, intervalTime); modifySimpleJobTime(triggerKey, intervalTime);
} else { } else {
addSimpleJob(jobKey, triggerKey, clz, intervalTime, jobDataMap); addSimpleJob(jobKey, triggerKey, clz, intervalTime, jobDataMap);
@ -265,7 +266,7 @@ public class QuartzManager {
} }
public static void addOrUpdateSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class clz, int intervalTime) throws SchedulerException { public void addOrUpdateSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class clz, int intervalTime) throws SchedulerException {
addOrUpdateSimpleJob(jobKey, triggerKey, clz, intervalTime, null); addOrUpdateSimpleJob(jobKey, triggerKey, clz, intervalTime, null);
} }
@ -279,23 +280,22 @@ public class QuartzManager {
* @param jobDataMap * @param jobDataMap
* @throws SchedulerException * @throws SchedulerException
*/ */
public static void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, JobDataMap jobDataMap) throws SchedulerException { public void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, JobDataMap jobDataMap) throws SchedulerException {
Scheduler sched = sf.getScheduler();
LogUtil.info("AddOrUpdateCronJob: " + jobKey.getName() + "," + triggerKey.getGroup()); LogUtil.info("AddOrUpdateCronJob: " + jobKey.getName() + "," + triggerKey.getGroup());
if (sched.checkExists(triggerKey)) { if (scheduler.checkExists(triggerKey)) {
modifyCronJobTime(triggerKey, cron); modifyCronJobTime(triggerKey, cron);
} else { } else {
addCronJob(jobKey, triggerKey, jobClass, cron, jobDataMap); addCronJob(jobKey, triggerKey, jobClass, cron, jobDataMap);
} }
} }
public static void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron) throws SchedulerException { public void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron) throws SchedulerException {
addOrUpdateCronJob(jobKey, triggerKey, jobClass, cron, null); addOrUpdateCronJob(jobKey, triggerKey, jobClass, cron, null);
} }
public static JobDataMap getDefaultJobDataMap(String resourceId, String expression, String userId) { public JobDataMap getDefaultJobDataMap(String resourceId, String expression, String userId) {
JobDataMap jobDataMap = new JobDataMap(); JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("resourceId", resourceId); jobDataMap.put("resourceId", resourceId);
jobDataMap.put("expression", expression); jobDataMap.put("expression", expression);

View File

@ -4,13 +4,10 @@ import com.alibaba.fastjson.JSON;
import io.metersphere.base.domain.Schedule; import io.metersphere.base.domain.Schedule;
import io.metersphere.base.domain.ScheduleExample; import io.metersphere.base.domain.ScheduleExample;
import io.metersphere.base.mapper.ScheduleMapper; import io.metersphere.base.mapper.ScheduleMapper;
import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.constants.ScheduleType;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils; import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.job.QuartzManager; import io.metersphere.job.sechedule.ScheduleManager;
import io.metersphere.job.sechedule.ApiTestJob;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.quartz.JobKey; import org.quartz.JobKey;
import org.quartz.SchedulerException; import org.quartz.SchedulerException;
@ -28,6 +25,8 @@ public class ScheduleService {
@Resource @Resource
private ScheduleMapper scheduleMapper; private ScheduleMapper scheduleMapper;
@Resource
private ScheduleManager scheduleManager;
public void addSchedule(Schedule schedule) { public void addSchedule(Schedule schedule) {
schedule.setId(UUID.randomUUID().toString()); schedule.setId(UUID.randomUUID().toString());
@ -73,11 +72,10 @@ public class ScheduleService {
try { try {
if (schedule.getEnable()) { if (schedule.getEnable()) {
LogUtil.error("初始化任务:" + JSON.toJSONString(schedule)); LogUtil.error("初始化任务:" + JSON.toJSONString(schedule));
QuartzManager.addOrUpdateCronJob(new JobKey(schedule.getKey(), schedule.getGroup()), scheduleManager.addOrUpdateCronJob(new JobKey(schedule.getKey(), schedule.getGroup()),
new TriggerKey(schedule.getKey(), schedule.getGroup()), Class.forName(schedule.getJob()), schedule.getValue(), new TriggerKey(schedule.getKey(), schedule.getGroup()), Class.forName(schedule.getJob()), schedule.getValue(),
QuartzManager.getDefaultJobDataMap(schedule.getResourceId(), schedule.getValue(), schedule.getUserId())); scheduleManager.getDefaultJobDataMap(schedule.getResourceId(), schedule.getValue(), schedule.getUserId()));
} }
Thread.sleep(1*60*1000);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error("初始化任务失败", e); LogUtil.error("初始化任务失败", e);
e.printStackTrace(); e.printStackTrace();
@ -100,14 +98,14 @@ public class ScheduleService {
String cronExpression = request.getValue(); String cronExpression = request.getValue();
if (enable != null && enable && StringUtils.isNotBlank(cronExpression)) { if (enable != null && enable && StringUtils.isNotBlank(cronExpression)) {
try { try {
QuartzManager.addOrUpdateCronJob(jobKey, triggerKey, clazz, cronExpression, QuartzManager.getDefaultJobDataMap(request.getResourceId(), cronExpression, SessionUtils.getUser().getId())); scheduleManager.addOrUpdateCronJob(jobKey, triggerKey, clazz, cronExpression, scheduleManager.getDefaultJobDataMap(request.getResourceId(), cronExpression, SessionUtils.getUser().getId()));
} catch (SchedulerException e) { } catch (SchedulerException e) {
LogUtil.error(e.getMessage(), e); LogUtil.error(e.getMessage(), e);
MSException.throwException("定时任务开启异常"); MSException.throwException("定时任务开启异常");
} }
} else { } else {
try { try {
QuartzManager.removeJob(jobKey, triggerKey); scheduleManager.removeJob(jobKey, triggerKey);
} catch (Exception e) { } catch (Exception e) {
MSException.throwException("定时任务关闭异常"); MSException.throwException("定时任务关闭异常");
} }

View File

@ -64,4 +64,8 @@ kafka.ssl.provider=
kafka.ssl.truststore-type= kafka.ssl.truststore-type=
# jmeter # jmeter
jmeter.home=/opt/jmeter jmeter.home=/opt/jmeter
# quartz
quartz.enabled=true
quartz.scheduler-name=msServerJob

View File

@ -1,3 +1,155 @@
-- quartz start
CREATE TABLE `qrtz_job_details` (
`SCHED_NAME` varchar(120) NOT NULL,
`JOB_NAME` varchar(200) NOT NULL,
`JOB_GROUP` varchar(200) NOT NULL,
`DESCRIPTION` varchar(250) DEFAULT NULL,
`JOB_CLASS_NAME` varchar(250) NOT NULL,
`IS_DURABLE` varchar(1) NOT NULL,
`IS_NONCONCURRENT` varchar(1) NOT NULL,
`IS_UPDATE_DATA` varchar(1) NOT NULL,
`REQUESTS_RECOVERY` varchar(1) NOT NULL,
`JOB_DATA` blob,
PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
KEY `IDX_QRTZ_J_REQ_RECOVERY` (`SCHED_NAME`,`REQUESTS_RECOVERY`),
KEY `IDX_QRTZ_J_GRP` (`SCHED_NAME`,`JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `qrtz_triggers` (
`SCHED_NAME` varchar(120) NOT NULL,
`TRIGGER_NAME` varchar(200) NOT NULL,
`TRIGGER_GROUP` varchar(200) NOT NULL,
`JOB_NAME` varchar(200) NOT NULL,
`JOB_GROUP` varchar(200) NOT NULL,
`DESCRIPTION` varchar(250) DEFAULT NULL,
`NEXT_FIRE_TIME` bigint(13) DEFAULT NULL,
`PREV_FIRE_TIME` bigint(13) DEFAULT NULL,
`PRIORITY` int(11) DEFAULT NULL,
`TRIGGER_STATE` varchar(16) NOT NULL,
`TRIGGER_TYPE` varchar(8) NOT NULL,
`START_TIME` bigint(13) NOT NULL,
`END_TIME` bigint(13) DEFAULT NULL,
`CALENDAR_NAME` varchar(200) DEFAULT NULL,
`MISFIRE_INSTR` smallint(2) DEFAULT NULL,
`JOB_DATA` blob,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
KEY `IDX_QRTZ_T_J` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
KEY `IDX_QRTZ_T_JG` (`SCHED_NAME`,`JOB_GROUP`),
KEY `IDX_QRTZ_T_C` (`SCHED_NAME`,`CALENDAR_NAME`),
KEY `IDX_QRTZ_T_G` (`SCHED_NAME`,`TRIGGER_GROUP`),
KEY `IDX_QRTZ_T_STATE` (`SCHED_NAME`,`TRIGGER_STATE`),
KEY `IDX_QRTZ_T_N_STATE` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
KEY `IDX_QRTZ_T_N_G_STATE` (`SCHED_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
KEY `IDX_QRTZ_T_NEXT_FIRE_TIME` (`SCHED_NAME`,`NEXT_FIRE_TIME`),
KEY `IDX_QRTZ_T_NFT_ST` (`SCHED_NAME`,`TRIGGER_STATE`,`NEXT_FIRE_TIME`),
KEY `IDX_QRTZ_T_NFT_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`),
KEY `IDX_QRTZ_T_NFT_ST_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_STATE`),
KEY `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `qrtz_job_details` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `qrtz_blob_triggers` (
`SCHED_NAME` varchar(120) NOT NULL,
`TRIGGER_NAME` varchar(200) NOT NULL,
`TRIGGER_GROUP` varchar(200) NOT NULL,
`BLOB_DATA` blob,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
KEY `SCHED_NAME` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `qrtz_calendars` (
`SCHED_NAME` varchar(120) NOT NULL,
`CALENDAR_NAME` varchar(200) NOT NULL,
`CALENDAR` blob NOT NULL,
PRIMARY KEY (`SCHED_NAME`,`CALENDAR_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `qrtz_cron_triggers` (
`SCHED_NAME` varchar(120) NOT NULL,
`TRIGGER_NAME` varchar(200) NOT NULL,
`TRIGGER_GROUP` varchar(200) NOT NULL,
`CRON_EXPRESSION` varchar(120) NOT NULL,
`TIME_ZONE_ID` varchar(80) DEFAULT NULL,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `qrtz_fired_triggers` (
`SCHED_NAME` varchar(120) NOT NULL,
`ENTRY_ID` varchar(95) NOT NULL,
`TRIGGER_NAME` varchar(200) NOT NULL,
`TRIGGER_GROUP` varchar(200) NOT NULL,
`INSTANCE_NAME` varchar(200) NOT NULL,
`FIRED_TIME` bigint(13) NOT NULL,
`SCHED_TIME` bigint(13) NOT NULL,
`PRIORITY` int(11) NOT NULL,
`STATE` varchar(16) NOT NULL,
`JOB_NAME` varchar(200) DEFAULT NULL,
`JOB_GROUP` varchar(200) DEFAULT NULL,
`IS_NONCONCURRENT` varchar(1) DEFAULT NULL,
`REQUESTS_RECOVERY` varchar(1) DEFAULT NULL,
PRIMARY KEY (`SCHED_NAME`,`ENTRY_ID`),
KEY `IDX_QRTZ_FT_TRIG_INST_NAME` (`SCHED_NAME`,`INSTANCE_NAME`),
KEY `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY` (`SCHED_NAME`,`INSTANCE_NAME`,`REQUESTS_RECOVERY`),
KEY `IDX_QRTZ_FT_J_G` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
KEY `IDX_QRTZ_FT_JG` (`SCHED_NAME`,`JOB_GROUP`),
KEY `IDX_QRTZ_FT_T_G` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
KEY `IDX_QRTZ_FT_TG` (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `qrtz_locks` (
`SCHED_NAME` varchar(120) NOT NULL,
`LOCK_NAME` varchar(40) NOT NULL,
PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `qrtz_paused_trigger_grps` (
`SCHED_NAME` varchar(120) NOT NULL,
`TRIGGER_GROUP` varchar(200) NOT NULL,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `qrtz_scheduler_state` (
`SCHED_NAME` varchar(120) NOT NULL,
`INSTANCE_NAME` varchar(200) NOT NULL,
`LAST_CHECKIN_TIME` bigint(13) NOT NULL,
`CHECKIN_INTERVAL` bigint(13) NOT NULL,
PRIMARY KEY (`SCHED_NAME`,`INSTANCE_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `qrtz_simple_triggers` (
`SCHED_NAME` varchar(120) NOT NULL,
`TRIGGER_NAME` varchar(200) NOT NULL,
`TRIGGER_GROUP` varchar(200) NOT NULL,
`REPEAT_COUNT` bigint(7) NOT NULL,
`REPEAT_INTERVAL` bigint(12) NOT NULL,
`TIMES_TRIGGERED` bigint(10) NOT NULL,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `qrtz_simprop_triggers` (
`SCHED_NAME` varchar(120) NOT NULL,
`TRIGGER_NAME` varchar(200) NOT NULL,
`TRIGGER_GROUP` varchar(200) NOT NULL,
`STR_PROP_1` varchar(512) DEFAULT NULL,
`STR_PROP_2` varchar(512) DEFAULT NULL,
`STR_PROP_3` varchar(512) DEFAULT NULL,
`INT_PROP_1` int(11) DEFAULT NULL,
`INT_PROP_2` int(11) DEFAULT NULL,
`LONG_PROP_1` bigint(20) DEFAULT NULL,
`LONG_PROP_2` bigint(20) DEFAULT NULL,
`DEC_PROP_1` decimal(13,4) DEFAULT NULL,
`DEC_PROP_2` decimal(13,4) DEFAULT NULL,
`BOOL_PROP_1` varchar(1) DEFAULT NULL,
`BOOL_PROP_2` varchar(1) DEFAULT NULL,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- quartz end
CREATE TABLE IF NOT EXISTS `schedule` ( CREATE TABLE IF NOT EXISTS `schedule` (
`id` varchar(50) NOT NULL COMMENT 'Schedule ID', `id` varchar(50) NOT NULL COMMENT 'Schedule ID',
`key` varchar(50) NOT NULL COMMENT 'Schedule Key', `key` varchar(50) NOT NULL COMMENT 'Schedule Key',