fix(接口测试): 嵌套事务拆分,解决并发过程可能产生死锁的方法

--bug=1020291 --user=赵勇 [接口测试]github#19759V2.2.1 执行接口自动化,点击调试出现死锁(出现频次高) https://www.tapd.cn/55049933/s/1308702
This commit is contained in:
fit2-zhao 2022-11-30 16:30:10 +08:00 committed by CaptainB
parent ecc81b245b
commit 2280ff3821
4 changed files with 57 additions and 58 deletions

View File

@ -2,10 +2,9 @@ package io.metersphere.service;
import io.metersphere.api.dto.automation.ApiTestReportVariable;
import io.metersphere.api.exec.scenario.ApiEnvironmentRunningParamService;
import io.metersphere.api.jmeter.utils.ReportStatusUtil;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiTestCaseMapper;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.PropertyConstant;
@ -14,12 +13,14 @@ import io.metersphere.commons.enums.ApiReportStatus;
import io.metersphere.commons.enums.ExecutionExecuteTypeEnum;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.DateUtils;
import io.metersphere.commons.vo.ResultVO;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.BaseSystemConfigDTO;
import io.metersphere.dto.ResultDTO;
import io.metersphere.notice.sender.NoticeModel;
import io.metersphere.notice.service.NoticeSendService;
import io.metersphere.service.definition.ApiDefinitionExecResultService;
import io.metersphere.service.definition.ApiTestCaseService;
import io.metersphere.service.scenario.ApiScenarioExecutionInfoService;
import io.metersphere.service.scenario.ApiScenarioReportService;
import io.metersphere.service.scenario.ApiScenarioReportStructureService;
@ -28,13 +29,11 @@ import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestResultService {
@Resource
private ApiDefinitionExecResultService apiDefinitionExecResultService;
@ -45,8 +44,6 @@ public class TestResultService {
@Resource
private ApiScenarioMapper apiScenarioMapper;
@Resource
private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper;
@Resource
private ApiEnvironmentRunningParamService apiEnvironmentRunningParamService;
@Resource
private RedisTemplateService redisTemplateService;
@ -55,7 +52,7 @@ public class TestResultService {
@Resource
private ApiScenarioReportStructureService apiScenarioReportStructureService;
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
private ApiTestCaseService apiTestCaseService;
// 场景
private static final List<String> scenarioRunModes = new ArrayList<>() {{
@ -142,6 +139,48 @@ public class TestResultService {
}
}
private ApiScenarioReport editReport(ResultDTO dto) {
// 更新报告状态
ResultVO resultVO = ReportStatusUtil.computedProcess(dto);
ApiScenarioReport report = apiScenarioReportService.editReport(dto.getReportType(), dto.getReportId(), resultVO.getStatus(), dto.getRunMode());
// 更新场景状态
ApiScenarioWithBLOBs scenario = apiScenarioMapper.selectByPrimaryKey(dto.getTestId());
if (scenario == null) {
scenario = apiScenarioMapper.selectByPrimaryKey(report.getScenarioId());
}
if (scenario != null) {
scenario.setLastResult(resultVO.getStatus());
scenario.setPassRate(resultVO.computerPassRate());
scenario.setReportId(dto.getReportId());
int executeTimes = 0;
if (scenario.getExecuteTimes() != null) {
executeTimes = scenario.getExecuteTimes().intValue();
}
scenario.setExecuteTimes(executeTimes + 1);
apiScenarioMapper.updateByPrimaryKey(scenario);
}
// 发送通知
if (scenario != null && report != null) {
apiScenarioReportService.sendNotice(scenario, report);
}
return report;
}
public ApiScenarioReport edit(ResultDTO dto) {
if (!StringUtils.equals(dto.getReportType(), RunModeConstants.SET_REPORT.toString())) {
// 更新控制台信息
apiScenarioReportStructureService.update(dto.getReportId(), dto.getConsole(), false);
}
if (StringUtils.equals(dto.getRunMode(), ApiRunMode.SCENARIO_PLAN.name())) {
return apiScenarioReportService.updatePlanCase(dto);
} else if (StringUtils.equalsAny(dto.getRunMode(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
return apiScenarioReportService.updateSchedulePlanCase(dto);
} else {
return this.editReport(dto);
}
}
public void testEnded(ResultDTO dto) {
// 删除串行资源锁
if (StringUtils.equals(dto.getRunType(), RunModeConstants.SERIAL.toString())) {
@ -152,7 +191,7 @@ public class TestResultService {
dto.setRequestResults(new LinkedList<>());
}
if (scenarioRunModes.contains(dto.getRunMode())) {
ApiScenarioReport scenarioReport = apiScenarioReportService.testEnded(dto);
ApiScenarioReport scenarioReport = edit(dto);
if (scenarioReport != null) {
String environment = StringUtils.EMPTY;
//执行人
@ -198,13 +237,13 @@ public class TestResultService {
ApiDefinitionExecResultExample example = new ApiDefinitionExecResultExample();
example.createCriteria().andIdEqualTo(dto.getReportId()).andStatusEqualTo(ApiReportStatus.RUNNING.name());
apiDefinitionExecResultMapper.updateByExampleSelective(record, example);
apiDefinitionExecResultService.updateByExampleSelective(record, example);
if (StringUtils.isNotEmpty(dto.getTestId())) {
ApiTestCaseWithBLOBs apiTestCase = new ApiTestCaseWithBLOBs();
apiTestCase.setLastResultId(dto.getReportId());
apiTestCase.setId(dto.getTestId());
apiTestCaseMapper.updateByPrimaryKeySelective(apiTestCase);
apiTestCaseService.updateByPrimaryKeySelective(apiTestCase);
}
}

View File

@ -473,4 +473,8 @@ public class ApiDefinitionExecResultService {
}
}
}
public void updateByExampleSelective(ApiDefinitionExecResultWithBLOBs resultWithBLOBs, ApiDefinitionExecResultExample resultExample) {
apiDefinitionExecResultMapper.updateByExampleSelective(resultWithBLOBs, resultExample);
}
}

View File

@ -1289,4 +1289,7 @@ public class ApiTestCaseService {
return extApiTestCaseMapper.selectApiCaseBasicInfoById(id);
}
public void updateByPrimaryKeySelective(ApiTestCaseWithBLOBs apiTestCase) {
apiTestCaseMapper.updateByPrimaryKeySelective(apiTestCase);
}
}

View File

@ -96,25 +96,6 @@ public class ApiScenarioReportService {
apiScenarioReportResultService.batchSave(dtos);
}
public ApiScenarioReport testEnded(ResultDTO dto) {
if (!StringUtils.equals(dto.getReportType(), RunModeConstants.SET_REPORT.toString())) {
// 更新控制台信息
apiScenarioReportStructureService.update(dto.getReportId(), dto.getConsole(), false);
}
// 优化当前执行携带结果作为状态判断依据
ApiScenarioReport scenarioReport;
if (StringUtils.equals(dto.getRunMode(), ApiRunMode.SCENARIO_PLAN.name())) {
scenarioReport = updatePlanCase(dto);
} else if (StringUtils.equalsAny(dto.getRunMode(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
scenarioReport = updateSchedulePlanCase(dto);
} else {
scenarioReport = updateScenario(dto);
}
// 串行队列
return scenarioReport;
}
public ApiScenarioReportResult get(String reportId, boolean selectReportContent) {
ApiScenarioReportResult reportResult = extApiScenarioReportMapper.get(reportId);
if (reportResult != null) {
@ -453,34 +434,6 @@ public class ApiScenarioReportService {
FixedCapacityUtil.remove(reportId);
}
public ApiScenarioReport updateScenario(ResultDTO dto) {
// 更新报告状态
ResultVO resultVO = ReportStatusUtil.computedProcess(dto);
ApiScenarioReport report = editReport(dto.getReportType(), dto.getReportId(), resultVO.getStatus(), dto.getRunMode());
// 更新场景状态
ApiScenarioWithBLOBs scenario = apiScenarioMapper.selectByPrimaryKey(dto.getTestId());
if (scenario == null) {
scenario = apiScenarioMapper.selectByPrimaryKey(report.getScenarioId());
}
if (scenario != null) {
scenario.setLastResult(resultVO.getStatus());
scenario.setPassRate(resultVO.computerPassRate());
scenario.setReportId(dto.getReportId());
int executeTimes = 0;
if (scenario.getExecuteTimes() != null) {
executeTimes = scenario.getExecuteTimes().intValue();
}
scenario.setExecuteTimes(executeTimes + 1);
apiScenarioMapper.updateByPrimaryKey(scenario);
}
// 发送通知
if (scenario != null && report != null) {
sendNotice(scenario, report);
}
return report;
}
public String getEnvironment(ApiScenarioWithBLOBs apiScenario) {
String environment = "未配置";
String environmentType = apiScenario.getEnvironmentType();
@ -508,7 +461,7 @@ public class ApiScenarioReportService {
return environment;
}
private void sendNotice(ApiScenarioWithBLOBs scenario, ApiScenarioReport result) {
public void sendNotice(ApiScenarioWithBLOBs scenario, ApiScenarioReport result) {
BeanMap beanMap = new BeanMap(scenario);