refactor(系统): 清理报告定时任务所有项目共用一个&项目启动时查询定时任务

This commit is contained in:
WangXu10 2024-01-29 11:43:59 +08:00 committed by 刘瑞斌
parent 6513bde610
commit e8233fe336
11 changed files with 237 additions and 12 deletions

View File

@ -7,6 +7,7 @@ import io.metersphere.sdk.file.FileCenter;
import io.metersphere.sdk.file.MinioRepository; import io.metersphere.sdk.file.MinioRepository;
import io.metersphere.sdk.util.CommonBeanFactory; import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.LogUtils; import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.service.BaseScheduleService;
import io.metersphere.system.service.PluginLoadService; import io.metersphere.system.service.PluginLoadService;
import io.minio.MinioClient; import io.minio.MinioClient;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@ -22,12 +23,18 @@ public class AppStartListener implements ApplicationRunner {
@Resource @Resource
private MinioClient minioClient; private MinioClient minioClient;
@Resource
private BaseScheduleService baseScheduleService;
@Override @Override
public void run(ApplicationArguments args) throws Exception { public void run(ApplicationArguments args) throws Exception {
LogUtils.info("================= 应用启动 ================="); LogUtils.info("================= 应用启动 =================");
// 初始化MinIO配置 // 初始化MinIO配置
((MinioRepository) FileCenter.getRepository(StorageType.MINIO)).init(minioClient); ((MinioRepository) FileCenter.getRepository(StorageType.MINIO)).init(minioClient);
LogUtils.info("初始化定时任务");
baseScheduleService.startEnableSchedules();
// 注册所有监听源 // 注册所有监听源
LogUtils.info("初始化接口事件源"); LogUtils.info("初始化接口事件源");
ApiEventSource apiEventSource = CommonBeanFactory.getBean(ApiEventSource.class); ApiEventSource apiEventSource = CommonBeanFactory.getBean(ApiEventSource.class);

View File

@ -705,8 +705,6 @@ INSERT INTO message_task_blob(id, template) VALUES (@bug_comment_reply_id, 'mess
-- 初始化定时任务数据
INSERT INTO schedule(`id`, `key`, `type`,`resource_type`, `value`, `job`, `enable`, `resource_id`, `create_user`, `create_time`, `update_time`, `project_id`, `name`, `config`) VALUES (UUID_SHORT(), '100001100001', 'CRON','CLEAN_REPORT', '0 0 2 * * ?', 'io.metersphere.project.job.CleanUpReportJob', true, '100001100001', 'admin', unix_timestamp() * 1000, unix_timestamp() * 1000, '100001100001', 'Clean Report Job', NULL);
-- 初始化默认项目版本配置项 -- 初始化默认项目版本配置项
INSERT INTO project_application (`project_id`, `type`, `type_value`) VALUES ('100001100001', 'VERSION_ENABLE', 'FALSE'); INSERT INTO project_application (`project_id`, `type`, `type_value`) VALUES ('100001100001', 'VERSION_ENABLE', 'FALSE');

View File

@ -1,3 +1,7 @@
//TODO 后续清理 合并完没问题再清理=====清理报告定时任务只有一个cron表达式凌晨定时扫描
/*
package io.metersphere.project.job; package io.metersphere.project.job;
import io.metersphere.system.schedule.BaseScheduleJob; import io.metersphere.system.schedule.BaseScheduleJob;
@ -23,3 +27,5 @@ public class CleanUpReportJob extends BaseScheduleJob {
return new TriggerKey(projectId, CleanUpReportJob.class.getName()); return new TriggerKey(projectId, CleanUpReportJob.class.getName());
} }
} }
*/

View File

@ -1,3 +1,6 @@
//TODO 后续清理合并完没问题再清理=====清理报告定时任务只有一个cron表达式凌晨定时扫描 创建项目不再创建定时任务
/*
package io.metersphere.project.service; package io.metersphere.project.service;
import io.metersphere.project.job.CleanUpReportJob; import io.metersphere.project.job.CleanUpReportJob;
@ -9,9 +12,11 @@ import io.metersphere.system.service.CreateProjectResourceService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
*/
/** /**
* @author wx * @author wx
*/ *//*
@Component @Component
public class CreateApplicationResourceService implements CreateProjectResourceService { public class CreateApplicationResourceService implements CreateProjectResourceService {
@ -41,3 +46,4 @@ public class CreateApplicationResourceService implements CreateProjectResourceSe
CleanUpReportJob.class); CleanUpReportJob.class);
} }
} }
*/

View File

@ -9,7 +9,6 @@ import io.metersphere.project.domain.ProjectApplication;
import io.metersphere.project.domain.ProjectApplicationExample; import io.metersphere.project.domain.ProjectApplicationExample;
import io.metersphere.project.dto.ModuleDTO; import io.metersphere.project.dto.ModuleDTO;
import io.metersphere.project.job.BugSyncJob; import io.metersphere.project.job.BugSyncJob;
import io.metersphere.project.job.CleanUpReportJob;
import io.metersphere.project.mapper.*; import io.metersphere.project.mapper.*;
import io.metersphere.project.request.ProjectApplicationRequest; import io.metersphere.project.request.ProjectApplicationRequest;
import io.metersphere.project.utils.ModuleSortUtils; import io.metersphere.project.utils.ModuleSortUtils;
@ -34,7 +33,6 @@ import io.metersphere.system.service.ServiceIntegrationService;
import io.metersphere.system.utils.ServiceUtils; import io.metersphere.system.utils.ServiceUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.pf4j.PluginWrapper; import org.pf4j.PluginWrapper;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -107,17 +105,18 @@ public class ProjectApplicationService {
} }
private void doBeforeUpdate(ProjectApplication application, String currentUser) { private void doBeforeUpdate(ProjectApplication application, String currentUser) {
String type = application.getType(); //TODO 后续清理合并完没问题再清理===== 清理报告只有一个定时任务项目配置时不需要在添加定时任务了
/*String type = application.getType();
if (StringUtils.equals(type, ProjectApplicationType.TEST_PLAN.TEST_PLAN_CLEAN_REPORT.name()) if (StringUtils.equals(type, ProjectApplicationType.TEST_PLAN.TEST_PLAN_CLEAN_REPORT.name())
|| StringUtils.equals(type, ProjectApplicationType.UI.UI_CLEAN_REPORT.name()) || StringUtils.equals(type, ProjectApplicationType.UI.UI_CLEAN_REPORT.name())
|| StringUtils.equals(type, ProjectApplicationType.LOAD_TEST.LOAD_TEST_CLEAN_REPORT.name()) || StringUtils.equals(type, ProjectApplicationType.LOAD_TEST.LOAD_TEST_CLEAN_REPORT.name())
|| StringUtils.equals(type, ProjectApplicationType.API.API_CLEAN_REPORT.name())) { || StringUtils.equals(type, ProjectApplicationType.API.API_CLEAN_REPORT.name())) {
//清除 测试计划/UI测试/性能测试/接口测试 报告 定时任务 //清除 测试计划/UI测试/性能测试/接口测试 报告 定时任务
this.doHandleSchedule(application, currentUser); this.doHandleSchedule(application, currentUser);
} }*/
} }
private void doHandleSchedule(ProjectApplication application, String currentUser) { /*private void doHandleSchedule(ProjectApplication application, String currentUser) {
String typeValue = application.getTypeValue(); String typeValue = application.getTypeValue();
String projectId = application.getProjectId(); String projectId = application.getProjectId();
Boolean enable = BooleanUtils.isTrue(Boolean.valueOf(typeValue)); Boolean enable = BooleanUtils.isTrue(Boolean.valueOf(typeValue));
@ -151,7 +150,7 @@ public class ProjectApplicationService {
CleanUpReportJob.class); CleanUpReportJob.class);
}); });
} }*/
/** /**

View File

@ -1,3 +1,4 @@
/*
package io.metersphere.project.controller; package io.metersphere.project.controller;
import io.metersphere.project.service.CreateApplicationResourceService; import io.metersphere.project.service.CreateApplicationResourceService;
@ -23,3 +24,4 @@ public class CreateApplicationResourceTests {
resourceService.createResources("test_project_id"); resourceService.createResources("test_project_id");
} }
} }
*/

View File

@ -0,0 +1,112 @@
package io.metersphere.system.job;
import com.fit2cloud.quartz.anno.QuartzScheduled;
import io.metersphere.project.domain.Project;
import io.metersphere.project.domain.ProjectApplication;
import io.metersphere.project.domain.ProjectApplicationExample;
import io.metersphere.project.domain.ProjectExample;
import io.metersphere.project.mapper.ProjectApplicationMapper;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.ProjectApplicationType;
import io.metersphere.system.service.BaseCleanUpReport;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author wx
*/
@Component
public class CleanUpReportJob {
@Resource
private ProjectMapper projectMapper;
@Resource
private ProjectApplicationMapper projectApplicationMapper;
@Autowired
private ApplicationContext applicationContext;
/**
* 清理报告定时任务所有项目共用一个
*/
@QuartzScheduled(cron = "0 0 1 * * ?")
public void cleanReport() {
long count = getProjectCount();
long pages = Double.valueOf(Math.ceil(count / 100.0)).longValue();
for (int i = 1; i <= pages; i++) {
Thread.startVirtualThread(new Runnable() {
@Override
public void run() {
ProjectExample example = new ProjectExample();
example.createCriteria().andDeletedEqualTo(false);
List<Project> projects = projectMapper.selectByExample(example);
projects.forEach(project -> {
ProjectApplicationExample applicationExample = new ProjectApplicationExample();
//test_plan
applicationExample.createCriteria().andProjectIdEqualTo(project.getId()).andTypeEqualTo(ProjectApplicationType.TEST_PLAN.TEST_PLAN_CLEAN_REPORT.name());
List<ProjectApplication> testPlan = projectApplicationMapper.selectByExample(applicationExample);
Map<String, String> map = new HashMap<>();
if (CollectionUtils.isNotEmpty(testPlan)) {
map.put(ProjectApplicationType.TEST_PLAN.TEST_PLAN_CLEAN_REPORT.name(), testPlan.get(0).getTypeValue());
} else {
map.put(ProjectApplicationType.TEST_PLAN.TEST_PLAN_CLEAN_REPORT.name(), "3M");
}
//ui
applicationExample.clear();
applicationExample.createCriteria().andProjectIdEqualTo(project.getId()).andTypeEqualTo(ProjectApplicationType.UI.UI_CLEAN_REPORT.name());
List<ProjectApplication> ui = projectApplicationMapper.selectByExample(applicationExample);
if (CollectionUtils.isNotEmpty(ui)) {
map.put(ProjectApplicationType.UI.UI_CLEAN_REPORT.name(), ui.get(0).getTypeValue());
} else {
map.put(ProjectApplicationType.UI.UI_CLEAN_REPORT.name(), "3M");
}
//load_test
applicationExample.clear();
applicationExample.createCriteria().andProjectIdEqualTo(project.getId()).andTypeEqualTo(ProjectApplicationType.LOAD_TEST.LOAD_TEST_CLEAN_REPORT.name());
List<ProjectApplication> loadTest = projectApplicationMapper.selectByExample(applicationExample);
if (CollectionUtils.isNotEmpty(loadTest)) {
map.put(ProjectApplicationType.LOAD_TEST.LOAD_TEST_CLEAN_REPORT.name(), loadTest.get(0).getTypeValue());
} else {
map.put(ProjectApplicationType.LOAD_TEST.LOAD_TEST_CLEAN_REPORT.name(), "3M");
}
//api
applicationExample.clear();
applicationExample.createCriteria().andProjectIdEqualTo(project.getId()).andTypeEqualTo(ProjectApplicationType.API.API_CLEAN_REPORT.name());
List<ProjectApplication> api = projectApplicationMapper.selectByExample(applicationExample);
if (CollectionUtils.isNotEmpty(api)) {
map.put(ProjectApplicationType.API.API_CLEAN_REPORT.name(), api.get(0).getTypeValue());
} else {
map.put(ProjectApplicationType.API.API_CLEAN_REPORT.name(), "3M");
}
Map<String, BaseCleanUpReport> beansOfType = applicationContext.getBeansOfType(BaseCleanUpReport.class);
beansOfType.forEach((k, v) -> {
v.cleanReport(map, project.getId());
});
});
}
});
}
}
private long getProjectCount() {
ProjectExample example = new ProjectExample();
example.createCriteria().andDeletedEqualTo(false);
return projectMapper.countByExample(example);
}
}

View File

@ -127,9 +127,8 @@ public class ScheduleManager {
/** /**
* 添加或修改 cronJob * 添加或修改 cronJob
*/ */
public void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class<? extends Job> jobClass, String cron, JobDataMap jobDataMap) public void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, JobDataMap jobDataMap)
throws SchedulerException { throws SchedulerException {
LogUtils.info("AddOrUpdateCronJob: " + jobKey.getName() + "," + triggerKey.getGroup()); LogUtils.info("AddOrUpdateCronJob: " + jobKey.getName() + "," + triggerKey.getGroup());
if (scheduler.checkExists(triggerKey)) { if (scheduler.checkExists(triggerKey)) {
@ -139,7 +138,7 @@ public class ScheduleManager {
} }
} }
public void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class<? extends Job> 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);
} }

View File

@ -0,0 +1,8 @@
package io.metersphere.system.service;
import java.util.Map;
public interface BaseCleanUpReport {
void cleanReport(Map<String, String> map, String projectId);
}

View File

@ -0,0 +1,55 @@
package io.metersphere.system.service;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.domain.Schedule;
import io.metersphere.system.domain.ScheduleExample;
import io.metersphere.system.mapper.ScheduleMapper;
import io.metersphere.system.schedule.ScheduleManager;
import jakarta.annotation.Resource;
import org.quartz.JobKey;
import org.quartz.TriggerKey;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
public class BaseScheduleService {
@Resource
private ScheduleMapper scheduleMapper;
@Resource
private ScheduleManager scheduleManager;
public void startEnableSchedules() {
List<Schedule> Schedules = getSchedule();
Schedules.forEach(schedule -> {
try {
if (schedule.getEnable()) {
LogUtils.info("初始化任务:" + JSON.toJSONString(schedule));
scheduleManager.addOrUpdateCronJob(new JobKey(schedule.getKey()),
new TriggerKey(schedule.getKey()), Class.forName(schedule.getJob()), schedule.getValue(),
scheduleManager.getDefaultJobDataMap(schedule, schedule.getValue(), schedule.getCreateUser()));
} else {
// 删除关闭的job
removeJob(schedule.getKey());
}
} catch (Exception e) {
LogUtils.error("初始化任务失败", e);
}
});
}
private List<Schedule> getSchedule() {
ScheduleExample example = new ScheduleExample();
example.createCriteria();
return scheduleMapper.selectByExample(example);
}
private void removeJob(String key) {
scheduleManager.removeJob(new JobKey(key), new TriggerKey(key));
}
}

View File

@ -0,0 +1,33 @@
package io.metersphere.system.controller;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.job.CleanUpReportJob;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.BooleanUtils;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class CleanReportJobTests extends BaseTest {
@Resource
private CleanUpReportJob cleanUpReportJob;
@Test
@Order(1)
@Sql(scripts = {"/dml/init_project.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void test() throws Exception {
BooleanUtils.isTrue(null);
cleanUpReportJob.cleanReport();
}
}