fix(测试计划执行): 增加quartz配置并合并1.14版本发现的针对多节点测试计划执行时的代码更改
增加quartz配置并合并1.14版本发现的针对多节点测试计划执行时的代码更改
This commit is contained in:
parent
c769f16a4b
commit
36961210f2
|
@ -9,6 +9,7 @@ import io.metersphere.base.mapper.ApiScenarioReportMapper;
|
|||
import io.metersphere.commons.constants.TestPlanApiExecuteStatus;
|
||||
import io.metersphere.commons.constants.TestPlanResourceType;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.track.dto.TestPlanReportExecuteCheckResultDTO;
|
||||
import io.metersphere.utils.LoggerUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
@ -20,6 +21,7 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author song.tianyang
|
||||
|
@ -30,17 +32,16 @@ import java.util.Map;
|
|||
public class TestPlanExecuteInfo {
|
||||
private String reportId;
|
||||
private String creator;
|
||||
private Map<String, String> apiCaseExecInfo = new HashMap<>();
|
||||
private Map<String, String> apiScenarioCaseExecInfo = new HashMap<>();
|
||||
private Map<String, String> loadCaseExecInfo = new HashMap<>();
|
||||
private Map<String, String> apiCaseExecInfo = new ConcurrentHashMap<>();
|
||||
private Map<String, String> apiScenarioCaseExecInfo = new ConcurrentHashMap<>();
|
||||
private Map<String, String> loadCaseExecInfo = new ConcurrentHashMap<>();
|
||||
|
||||
private Map<String, String> apiCaseExecuteThreadMap = new HashMap<>();
|
||||
private Map<String, String> apiScenarioThreadMap = new HashMap<>();
|
||||
private Map<String, String> loadCaseReportIdMap = new HashMap<>();
|
||||
|
||||
private Map<String, String> apiCaseReportMap = new HashMap<>();
|
||||
private Map<String, String> apiScenarioReportMap = new HashMap<>();
|
||||
private Map<String, String> apiCaseExecuteThreadMap = new ConcurrentHashMap<>();
|
||||
private Map<String, String> apiScenarioThreadMap = new ConcurrentHashMap<>();
|
||||
private Map<String, String> loadCaseReportIdMap = new ConcurrentHashMap<>();
|
||||
|
||||
private Map<String, String> apiCaseReportMap = new ConcurrentHashMap<>();
|
||||
private Map<String, String> apiScenarioReportMap = new ConcurrentHashMap<>();
|
||||
private boolean reportDataInDataBase;
|
||||
|
||||
int lastUnFinishedNumCount = 0;
|
||||
|
@ -83,7 +84,8 @@ public class TestPlanExecuteInfo {
|
|||
}
|
||||
}
|
||||
|
||||
public synchronized int countUnFinishedNum() {
|
||||
public synchronized TestPlanReportExecuteCheckResultDTO countUnFinishedNum() {
|
||||
TestPlanReportExecuteCheckResultDTO executeCheck = new TestPlanReportExecuteCheckResultDTO();
|
||||
int unFinishedCount = 0;
|
||||
|
||||
this.isApiCaseAllExecuted = true;
|
||||
|
@ -129,8 +131,22 @@ public class TestPlanExecuteInfo {
|
|||
LoggerUtil.info("执行的报告还在队列中,重置超时时间");
|
||||
lastUnFinishedNumCount = unFinishedCount;
|
||||
lastFinishedNumCountTime = System.currentTimeMillis();
|
||||
executeCheck.setFinishedCaseChanged(true);
|
||||
} else if (unFinishedCount == 0) {
|
||||
executeCheck.setFinishedCaseChanged(true);
|
||||
} else {
|
||||
executeCheck.setFinishedCaseChanged(false);
|
||||
}
|
||||
return unFinishedCount;
|
||||
|
||||
executeCheck.setTimeOut(false);
|
||||
if (unFinishedCount > 0) {
|
||||
//20分钟没有案例执行结果更新,则定位超时
|
||||
long nowTime = System.currentTimeMillis();
|
||||
if (nowTime - lastFinishedNumCountTime > 1200000) {
|
||||
executeCheck.setTimeOut(true);
|
||||
}
|
||||
}
|
||||
return executeCheck;
|
||||
}
|
||||
|
||||
public Map<String, Map<String, String>> getExecutedResult() {
|
||||
|
@ -228,7 +244,7 @@ public class TestPlanExecuteInfo {
|
|||
this.countUnFinishedNum();
|
||||
}
|
||||
|
||||
public void updateReport(Map<String, String> apiCaseExecResultInfo, Map<String, String> apiScenarioCaseExecResultInfo) {
|
||||
public synchronized void updateReport(Map<String, String> apiCaseExecResultInfo, Map<String, String> apiScenarioCaseExecResultInfo) {
|
||||
if (MapUtils.isNotEmpty(apiCaseExecResultInfo)) {
|
||||
this.apiCaseReportMap.putAll(apiCaseExecResultInfo);
|
||||
}
|
||||
|
@ -236,6 +252,35 @@ public class TestPlanExecuteInfo {
|
|||
if (MapUtils.isNotEmpty(apiScenarioCaseExecResultInfo)) {
|
||||
this.apiScenarioReportMap.putAll(apiScenarioCaseExecResultInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getRunningApiCaseReportMap() {
|
||||
//key: reportId, value: testPlanApiCaseId
|
||||
Map<String, String> returnMap = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : apiCaseExecInfo.entrySet()) {
|
||||
String planCaseId = entry.getKey();
|
||||
String status = entry.getValue();
|
||||
if (StringUtils.equalsIgnoreCase(status, TestPlanApiExecuteStatus.RUNNING.name())) {
|
||||
if (apiCaseExecuteThreadMap.containsKey(planCaseId)) {
|
||||
returnMap.put(apiCaseExecuteThreadMap.get(planCaseId), planCaseId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnMap;
|
||||
}
|
||||
|
||||
public Map<String, String> getRunningScenarioReportMap() {
|
||||
//key: reportId, value: testPlanApiScenarioId
|
||||
Map<String, String> returnMap = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : apiScenarioCaseExecInfo.entrySet()) {
|
||||
String planScenarioId = entry.getKey();
|
||||
String status = entry.getValue();
|
||||
if (StringUtils.equalsIgnoreCase(status, TestPlanApiExecuteStatus.RUNNING.name())) {
|
||||
if (apiScenarioThreadMap.containsKey(planScenarioId)) {
|
||||
returnMap.put(apiScenarioThreadMap.get(planScenarioId), planScenarioId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnMap;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package io.metersphere.api.cache;
|
||||
|
||||
import io.metersphere.commons.constants.TestPlanApiExecuteStatus;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -50,8 +51,12 @@ public class TestPlanReportExecuteCatch {
|
|||
}
|
||||
|
||||
public synchronized static boolean containsReport(String reportId) {
|
||||
if(StringUtils.isEmpty(reportId)){
|
||||
return false;
|
||||
}else {
|
||||
return testPlanReportMap != null && testPlanReportMap.containsKey(reportId);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static void updateApiTestPlanExecuteInfo(String reportId,
|
||||
Map<String, String> apiCaseExecInfo, Map<String, String> apiScenarioCaseExecInfo, Map<String, String> loadCaseExecInfo) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.metersphere.job.sechedule;
|
|||
import io.metersphere.commons.constants.ReportTriggerMode;
|
||||
import io.metersphere.commons.constants.ScheduleGroup;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.track.service.TestPlanService;
|
||||
import org.quartz.*;
|
||||
|
||||
|
@ -16,25 +17,10 @@ import org.quartz.*;
|
|||
public class TestPlanTestJob extends MsScheduleJob {
|
||||
private String projectID;
|
||||
|
||||
|
||||
// private PerformanceTestService performanceTestService;
|
||||
// private TestPlanScenarioCaseService testPlanScenarioCaseService;
|
||||
// private TestPlanApiCaseService testPlanApiCaseService;
|
||||
// private ApiTestCaseService apiTestCaseService;
|
||||
// private TestPlanReportService testPlanReportService;
|
||||
// private TestPlanLoadCaseService testPlanLoadCaseService;
|
||||
private TestPlanService testPlanService;
|
||||
|
||||
public TestPlanTestJob() {
|
||||
// this.performanceTestService = CommonBeanFactory.getBean(PerformanceTestService.class);
|
||||
// this.testPlanScenarioCaseService = CommonBeanFactory.getBean(TestPlanScenarioCaseService.class);
|
||||
// this.testPlanApiCaseService = CommonBeanFactory.getBean(TestPlanApiCaseService.class);
|
||||
// this.apiTestCaseService = CommonBeanFactory.getBean(ApiTestCaseService.class);
|
||||
// this.testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class);
|
||||
// this.testPlanLoadCaseService = CommonBeanFactory.getBean(TestPlanLoadCaseService.class);
|
||||
this.testPlanService = CommonBeanFactory.getBean(TestPlanService.class);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,7 +49,17 @@ public class TestPlanTestJob extends MsScheduleJob {
|
|||
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
|
||||
String config = jobDataMap.getString("config");
|
||||
|
||||
testPlanService.run(this.resourceId, this.projectID, this.userId, ReportTriggerMode.SCHEDULE.name(),config);
|
||||
String runResourceId = this.resourceId;
|
||||
String runProjectId = this.projectID;
|
||||
String runUserId = this.userId;
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtil.info("Start test_plan_scehdule. test_plan_id:" + runResourceId);
|
||||
testPlanService.run(runResourceId, runProjectId, runUserId, ReportTriggerMode.SCHEDULE.name(),config);
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public static JobKey getJobKey(String testId) {
|
||||
|
|
|
@ -68,6 +68,14 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
|
|||
|
||||
@Value("${jmeter.home}")
|
||||
private String jmeterHome;
|
||||
@Value("${quartz.properties.org.quartz.jobStore.acquireTriggersWithinLock}")
|
||||
private String acquireTriggersWithinLock;
|
||||
@Value("${quartz.enabled}")
|
||||
private boolean quartzEnable;
|
||||
@Value("${quartz.scheduler-name}")
|
||||
private String quartzScheduleName;
|
||||
@Value("${quartz.thread-count}")
|
||||
private int quartzThreadCount;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
|
||||
|
@ -99,7 +107,12 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
|
|||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
LogUtil.info("开始启动定时任务。 相关设置:" +
|
||||
"quartz.acquireTriggersWithinLock :" + acquireTriggersWithinLock + "\r\n" +
|
||||
"quartz.enabled :" + quartzEnable + "\r\n" +
|
||||
"quartz.scheduler-name :" + quartzScheduleName + "\r\n" +
|
||||
"quartz.thread-count :" + quartzThreadCount + "\r\n"
|
||||
);
|
||||
scheduleService.startEnableSchedules();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package io.metersphere.track.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestPlanReportExecuteCheckResultDTO {
|
||||
private boolean isTimeOut;
|
||||
private boolean isFinishedCaseChanged;
|
||||
}
|
|
@ -81,7 +81,9 @@ public class TestPlanReportService {
|
|||
@Resource
|
||||
ExtTestPlanApiCaseMapper extTestPlanApiCaseMapper;
|
||||
@Resource
|
||||
ApiTestCaseMapper apiTestCaseMapper;
|
||||
ExtApiDefinitionExecResultMapper extApiDefinitionExecResultMapper;
|
||||
@Resource
|
||||
ExtApiScenarioReportMapper extApiScenarioReportMapper;
|
||||
@Resource
|
||||
LoadTestReportMapper loadTestReportMapper;
|
||||
@Resource
|
||||
|
@ -551,8 +553,6 @@ public class TestPlanReportService {
|
|||
boolean scenarioIsOk = executeInfo.isScenarioAllExecuted();
|
||||
boolean performanceIsOk = executeInfo.isLoadCaseAllExecuted();
|
||||
|
||||
testPlanLog.info("ReportId[" + testPlanReport.getId() + "] count over. Testplan Execute Result: Api is over ->" + apiCaseIsOk + "; scenario is over ->" + scenarioIsOk + "; performance is over ->" + performanceIsOk);
|
||||
|
||||
if (apiCaseIsOk) {
|
||||
testPlanReport.setIsApiCaseExecuting(false);
|
||||
}
|
||||
|
@ -1075,13 +1075,17 @@ public class TestPlanReportService {
|
|||
}
|
||||
|
||||
public void countReport(String planReportId) {
|
||||
boolean isTimeOut = this.checkTestPlanReportIsTimeOut(planReportId);
|
||||
if (isTimeOut) {
|
||||
TestPlanReportExecuteCheckResultDTO checkResult = this.checkTestPlanReportIsTimeOut(planReportId);
|
||||
testPlanLog.info("Check PlanReport:" + planReportId + "; result: "+ JSON.toJSONString(checkResult));
|
||||
if (checkResult.isTimeOut()) {
|
||||
//判断是否超时。超时时强行停止任务
|
||||
TestPlanReportExecuteCatch.finishAllTask(planReportId);
|
||||
checkResult.setFinishedCaseChanged(true);
|
||||
}
|
||||
if(checkResult.isFinishedCaseChanged()){
|
||||
this.updateExecuteApis(planReportId);
|
||||
}
|
||||
}
|
||||
|
||||
public TestPlanSimpleReportDTO getReport(String reportId) {
|
||||
TestPlanReportContentExample example = new TestPlanReportContentExample();
|
||||
|
@ -1216,19 +1220,61 @@ public class TestPlanReportService {
|
|||
testPlanReportContentMapper.updateByExampleSelective(bloBs,example);
|
||||
}
|
||||
|
||||
private boolean checkTestPlanReportIsTimeOut(String planReportId) {
|
||||
private TestPlanReportExecuteCheckResultDTO checkTestPlanReportIsTimeOut(String planReportId) {
|
||||
//同步数据库更新状态信息
|
||||
try {
|
||||
this.syncReportStatus(planReportId);
|
||||
} catch (Exception e) {
|
||||
LogUtil.info("联动数据库同步执行状态失败! " + e.getMessage());
|
||||
LogUtil.error(e);
|
||||
}
|
||||
TestPlanExecuteInfo executeInfo = TestPlanReportExecuteCatch.getTestPlanExecuteInfo(planReportId);
|
||||
int unFinishNum = executeInfo.countUnFinishedNum();
|
||||
if (unFinishNum > 0) {
|
||||
//20分钟没有案例执行结果更新,则定位超时
|
||||
long lastCountTime = executeInfo.getLastFinishedNumCountTime();
|
||||
long nowTime = System.currentTimeMillis();
|
||||
testPlanLog.info("ReportId: ["+planReportId+"]; timeCount:"+ (nowTime - lastCountTime));
|
||||
if (nowTime - lastCountTime > 1200000) {
|
||||
return true;
|
||||
TestPlanReportExecuteCheckResultDTO checkResult = executeInfo.countUnFinishedNum();
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
private void syncReportStatus(String planReportId) {
|
||||
if (TestPlanReportExecuteCatch.containsReport(planReportId)) {
|
||||
TestPlanExecuteInfo executeInfo = TestPlanReportExecuteCatch.getTestPlanExecuteInfo(planReportId);
|
||||
if (executeInfo != null) {
|
||||
//同步接口案例结果
|
||||
Map<String, String> updateCaseStatusMap = new HashMap<>();
|
||||
Map<String, String> apiCaseReportMap = executeInfo.getRunningApiCaseReportMap();
|
||||
if (MapUtils.isNotEmpty(apiCaseReportMap)) {
|
||||
List<ApiDefinitionExecResult> execList = extApiDefinitionExecResultMapper.selectStatusByIdList(apiCaseReportMap.keySet());
|
||||
for (ApiDefinitionExecResult report : execList) {
|
||||
String reportId = report.getId();
|
||||
String status = report.getStatus();
|
||||
if (!StringUtils.equalsAnyIgnoreCase(status, "Running", "Waiting")) {
|
||||
String planCaseId = apiCaseReportMap.get(reportId);
|
||||
if (StringUtils.isNotEmpty(planCaseId)) {
|
||||
updateCaseStatusMap.put(planCaseId, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//同步场景结果
|
||||
Map<String, String> updateScenarioStatusMap = new HashMap<>();
|
||||
Map<String, String> scenarioReportMap = executeInfo.getRunningScenarioReportMap();
|
||||
if (MapUtils.isNotEmpty(scenarioReportMap)) {
|
||||
List<ApiScenarioReport> reportList = extApiScenarioReportMapper.selectStatusByIds(scenarioReportMap.keySet());
|
||||
for (ApiScenarioReport report : reportList) {
|
||||
String reportId = report.getId();
|
||||
String status = report.getStatus();
|
||||
if (!StringUtils.equalsAnyIgnoreCase(status, "Running", "Waiting")) {
|
||||
String planScenarioId = scenarioReportMap.get(reportId);
|
||||
if (StringUtils.isNotEmpty(planScenarioId)) {
|
||||
updateScenarioStatusMap.put(planScenarioId, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
testPlanLog.info("ReportID:"+planReportId+" 本次数据库同步,案例ID:"+JSON.toJSONString(apiCaseReportMap.keySet())+";场景ID:"+JSON.toJSONString(scenarioReportMap.keySet())+"; 同步结果,案例:"+JSON.toJSONString(updateCaseStatusMap)+";场景:"+JSON.toJSONString(updateScenarioStatusMap));
|
||||
TestPlanReportExecuteCatch.updateApiTestPlanExecuteInfo(planReportId, updateCaseStatusMap, updateScenarioStatusMap, null);
|
||||
}else {
|
||||
testPlanLog.info("同步数据库查询执行信息失败! 报告ID在缓存中未找到!"+planReportId);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void finishTestPlanReport(String planReportId) {
|
||||
|
@ -1239,5 +1285,4 @@ public class TestPlanReportService {
|
|||
}
|
||||
TestPlanReportExecuteCatch.remove(planReportId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ server.ssl.key-alias=localhost
|
|||
|
||||
# Hikari
|
||||
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
|
||||
spring.datasource.hikari.maximum-pool-size=100
|
||||
spring.datasource.hikari.maximum-pool-size=200
|
||||
spring.datasource.hikari.auto-commit=true
|
||||
spring.datasource.hikari.idle-timeout=10000
|
||||
spring.datasource.hikari.pool-name=DatebookHikariCP
|
||||
|
@ -23,7 +23,7 @@ spring.datasource.hikari.connection-test-query=SELECT 1
|
|||
spring.datasource.quartz.url=${spring.datasource.url}
|
||||
spring.datasource.quartz.username=${spring.datasource.username}
|
||||
spring.datasource.quartz.password=${spring.datasource.password}
|
||||
spring.datasource.quartz.hikari.maximum-pool-size=50
|
||||
spring.datasource.quartz.hikari.maximum-pool-size=200
|
||||
spring.datasource.quartz.hikari.auto-commit=true
|
||||
spring.datasource.quartz.hikari.idle-timeout=10000
|
||||
spring.datasource.quartz.hikari.pool-name=DatebookHikariCP
|
||||
|
@ -92,7 +92,8 @@ jmeter.home=/opt/jmeter
|
|||
# quartz
|
||||
quartz.enabled=true
|
||||
quartz.scheduler-name=msServerJob
|
||||
quartz.thread-count=30
|
||||
quartz.thread-count=60
|
||||
quartz.properties.org.quartz.jobStore.acquireTriggersWithinLock=true
|
||||
# file upload
|
||||
spring.servlet.multipart.max-file-size=500MB
|
||||
spring.servlet.multipart.max-request-size=500MB
|
||||
|
|
Loading…
Reference in New Issue