fix(测试跟踪): 同步缺陷异步执行无法获取请求头

This commit is contained in:
song-cc-rock 2023-04-25 12:00:13 +08:00 committed by jianxing
parent 136117de74
commit 1cc2326c6f
4 changed files with 152 additions and 102 deletions

View File

@ -26,6 +26,7 @@ import io.metersphere.request.testcase.AuthUserIssueRequest;
import io.metersphere.request.testcase.IssuesCountRequest; import io.metersphere.request.testcase.IssuesCountRequest;
import io.metersphere.service.BaseCheckPermissionService; import io.metersphere.service.BaseCheckPermissionService;
import io.metersphere.service.IssuesService; import io.metersphere.service.IssuesService;
import io.metersphere.service.IssuesSyncService;
import io.metersphere.service.PlatformPluginService; import io.metersphere.service.PlatformPluginService;
import io.metersphere.xpack.track.dto.*; import io.metersphere.xpack.track.dto.*;
import io.metersphere.xpack.track.dto.request.IssuesRequest; import io.metersphere.xpack.track.dto.request.IssuesRequest;
@ -47,6 +48,8 @@ public class IssuesController {
@Resource @Resource
private IssuesService issuesService; private IssuesService issuesService;
@Resource @Resource
private IssuesSyncService issuesSyncService;
@Resource
private BaseCheckPermissionService baseCheckPermissionService; private BaseCheckPermissionService baseCheckPermissionService;
@Resource @Resource
private PlatformPluginService platformPluginService; private PlatformPluginService platformPluginService;
@ -159,12 +162,12 @@ public class IssuesController {
@GetMapping("/sync/{projectId}") @GetMapping("/sync/{projectId}")
public void syncThirdPartyIssues(@PathVariable String projectId) { public void syncThirdPartyIssues(@PathVariable String projectId) {
issuesService.syncThirdPartyIssues(projectId); issuesSyncService.syncIssues(projectId);
} }
@PostMapping("/sync/all") @PostMapping("/sync/all")
public void syncThirdPartyAllIssues(@RequestBody IssueSyncRequest request) { public void syncThirdPartyAllIssues(@RequestBody IssueSyncRequest request) {
issuesService.syncThirdPartyAllIssues(request); issuesSyncService.syncAllIssues(request);
} }
@GetMapping("/sync/check/{projectId}") @GetMapping("/sync/check/{projectId}")

View File

@ -72,6 +72,7 @@ import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils; import org.mybatis.spring.SqlSessionUtils;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -95,6 +96,9 @@ public class IssuesService {
@Resource @Resource
private TrackProjectService trackProjectService; private TrackProjectService trackProjectService;
@Resource @Resource
@Lazy
private IssuesSyncService issuesSyncService;
@Resource
private BaseUserService baseUserService; private BaseUserService baseUserService;
@Resource @Resource
private BaseProjectService baseProjectService; private BaseProjectService baseProjectService;
@ -146,9 +150,6 @@ public class IssuesService {
private UserService userService; private UserService userService;
@Resource @Resource
private BasePluginService basePluginService; private BasePluginService basePluginService;
@Resource
@Lazy
private IssuesService issuesService;
private static final String SYNC_THIRD_PARTY_ISSUES_KEY = "ISSUE:SYNC"; private static final String SYNC_THIRD_PARTY_ISSUES_KEY = "ISSUE:SYNC";
private static final String SYNC_THIRD_PARTY_ISSUES_ERROR_KEY = "ISSUE:SYNC:ERROR"; private static final String SYNC_THIRD_PARTY_ISSUES_ERROR_KEY = "ISSUE:SYNC:ERROR";
@ -877,8 +878,7 @@ public class IssuesService {
List<String> projectIds = trackProjectService.getThirdPartProjectIds(); List<String> projectIds = trackProjectService.getThirdPartProjectIds();
projectIds.forEach(id -> { projectIds.forEach(id -> {
try { try {
// 使用代理对象调用防止事务注解失效 issuesSyncService.syncIssues(id);
issuesService.syncThirdPartyIssues(id);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e.getMessage(), e); LogUtil.error(e.getMessage(), e);
} }
@ -941,47 +941,29 @@ public class IssuesService {
stringRedisTemplate.delete(SYNC_THIRD_PARTY_ISSUES_ERROR_KEY + ":" + projectId); stringRedisTemplate.delete(SYNC_THIRD_PARTY_ISSUES_ERROR_KEY + ":" + projectId);
} }
@Async
@Transactional(propagation = Propagation.REQUIRES_NEW) @Transactional(propagation = Propagation.REQUIRES_NEW)
public void syncThirdPartyIssues(String projectId) { public void syncThirdPartyIssues(List<IssuesDao> issues, IssuesRequest issuesRequest, Project project) {
if (StringUtils.isNotBlank(projectId)) { try {
String syncValue = getSyncKey(projectId); if (PlatformPluginService.isPluginPlatform(project.getPlatform())) {
if (StringUtils.isEmpty(syncValue)) { // 分批处理
setSyncKey(projectId); SubListUtil.dealForSubList(issues, 500, (subIssue) ->
Project project = baseProjectService.getProjectById(projectId); syncPluginThirdPartyIssues(subIssue, project, issuesRequest.getDefaultCustomFields()));
List<IssuesDao> issues = extIssuesMapper.getIssueForSync(projectId, project.getPlatform()); } else {
IssuesPlatform platform = IssueFactory.createPlatform(project.getPlatform(), issuesRequest);
if (CollectionUtils.isEmpty(issues)) { syncThirdPartyIssues(platform::syncIssues, project, issues);
deleteSyncKey(projectId);
} else {
new Thread(() -> {
IssuesRequest issuesRequest = new IssuesRequest();
issuesRequest.setProjectId(projectId);
issuesRequest.setWorkspaceId(project.getWorkspaceId());
try {
issuesRequest.setDefaultCustomFields(getDefaultCustomField(project));
if (PlatformPluginService.isPluginPlatform(project.getPlatform())) {
// 分批处理
SubListUtil.dealForSubList(issues, 500, (subIssue) ->
syncPluginThirdPartyIssues(subIssue, project, issuesRequest.getDefaultCustomFields()));
} else {
IssuesPlatform platform = IssueFactory.createPlatform(project.getPlatform(), issuesRequest);
syncThirdPartyIssues(platform::syncIssues, project, issues);
}
} catch (Exception e) {
LogUtil.error(e);
// 同步缺陷异常, 当前同步错误信息 -> Redis(check接口获取)
setSyncErrorMsg(projectId, e.getMessage());
} finally {
// 异常或正常结束都得删除当前项目执行同步的Key
deleteSyncKey(projectId);
}
}).start();
}
} }
} catch (Exception e) {
LogUtil.error(e);
// 同步缺陷异常, 当前同步错误信息 -> Redis(check接口获取)
setSyncErrorMsg(project.getId(), e.getMessage());
} finally {
// 异常或正常结束都得删除当前项目执行同步的Key
deleteSyncKey(project.getId());
} }
} }
private String getDefaultCustomField(Project project) { public String getDefaultCustomField(Project project) {
if (isThirdPartTemplate(project)) { if (isThirdPartTemplate(project)) {
return null; return null;
} }
@ -1938,35 +1920,21 @@ public class IssuesService {
&& platformPluginService.isThirdPartTemplateSupport(project.getPlatform()); && platformPluginService.isThirdPartTemplateSupport(project.getPlatform());
} }
public void syncThirdPartyAllIssues(IssueSyncRequest syncRequest) { @Async
syncRequest.setProjectId(syncRequest.getProjectId()); public void syncThirdPartyAllIssues(IssueSyncRequest syncRequest, Project project) {
XpackIssueService xpackIssueService = CommonBeanFactory.getBean(XpackIssueService.class); try {
if (StringUtils.isNotBlank(syncRequest.getProjectId())) { XpackIssueService xpackIssueService = CommonBeanFactory.getBean(XpackIssueService.class);
// 获取当前项目执行同步缺陷Key xpackIssueService.syncThirdPartyIssues(project, syncRequest);
String syncValue = getSyncKey(syncRequest.getProjectId()); if (platformPluginService.isPluginPlatform(project.getPlatform())) {
if (StringUtils.isEmpty(syncValue)) { syncAllPluginIssueAttachment(project, syncRequest);
// 同步Key不存在, 设置保证唯一性, 并开始同步
setSyncKey(syncRequest.getProjectId());
new Thread(() -> {
try {
Project project = baseProjectService.getProjectById(syncRequest.getProjectId());
if (!isThirdPartTemplate(project)) {
syncRequest.setDefaultCustomFields(getDefaultCustomFields(syncRequest.getProjectId()));
}
xpackIssueService.syncThirdPartyIssues(project, syncRequest);
if (platformPluginService.isPluginPlatform(project.getPlatform())) {
syncAllPluginIssueAttachment(project, syncRequest);
}
} catch (Exception e) {
LogUtil.error(e);
// 同步缺陷异常, 当前同步错误信息 -> Redis(check接口获取)
setSyncErrorMsg(syncRequest.getProjectId(), e.getMessage());
} finally {
// 异常或正常结束都得删除当前项目执行同步的Key
deleteSyncKey(syncRequest.getProjectId());
}
}).start();
} }
} catch (Exception e) {
LogUtil.error(e);
// 同步缺陷异常, 当前同步错误信息 -> Redis(check接口获取)
setSyncErrorMsg(syncRequest.getProjectId(), e.getMessage());
} finally {
// 异常或正常结束都得删除当前项目执行同步的Key
deleteSyncKey(syncRequest.getProjectId());
} }
} }
@ -1977,7 +1945,6 @@ public class IssuesService {
Platform platform = platformPluginService.getPlatform(project.getPlatform(), project.getWorkspaceId()); Platform platform = platformPluginService.getPlatform(project.getPlatform(), project.getWorkspaceId());
SyncAllIssuesRequest syncAllIssuesRequest = new SyncAllIssuesRequest(); SyncAllIssuesRequest syncAllIssuesRequest = new SyncAllIssuesRequest();
BeanUtils.copyBean(syncAllIssuesRequest, issueSyncRequest); BeanUtils.copyBean(syncAllIssuesRequest, issueSyncRequest);
syncAllIssuesRequest.setDefaultCustomFields(getDefaultCustomField(project));
syncAllIssuesRequest.setProjectConfig(PlatformPluginService.getCompatibleProjectConfig(project)); syncAllIssuesRequest.setProjectConfig(PlatformPluginService.getCompatibleProjectConfig(project));
syncAllIssuesRequest.setHandleSyncFunc(issueSyncRequest.getHandleSyncFunc()); syncAllIssuesRequest.setHandleSyncFunc(issueSyncRequest.getHandleSyncFunc());
platform.syncAllIssues(syncAllIssuesRequest); platform.syncAllIssues(syncAllIssuesRequest);

View File

@ -0,0 +1,85 @@
package io.metersphere.service;
import io.metersphere.base.domain.Project;
import io.metersphere.base.mapper.ext.ExtIssuesMapper;
import io.metersphere.commons.exception.MSException;
import io.metersphere.xpack.track.dto.IssueSyncRequest;
import io.metersphere.xpack.track.dto.IssuesDao;
import io.metersphere.xpack.track.dto.request.IssuesRequest;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @author song-cc-rock
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class IssuesSyncService {
@Resource
private IssuesService issuesService;
@Resource
private BaseProjectService baseProjectService;
@Resource
private ExtIssuesMapper extIssuesMapper;
/**
* xpack用户
* @param syncRequest 同步参数
*/
public void syncAllIssues(IssueSyncRequest syncRequest) {
try {
if (StringUtils.isNotBlank(syncRequest.getProjectId())) {
// 获取当前项目执行同步缺陷Key
String syncValue = issuesService.getSyncKey(syncRequest.getProjectId());
if (StringUtils.isEmpty(syncValue)) {
// 同步Key不存在, 设置保证唯一性, 并开始同步
issuesService.setSyncKey(syncRequest.getProjectId());
Project project = baseProjectService.getProjectById(syncRequest.getProjectId());
if (!issuesService.isThirdPartTemplate(project)) {
syncRequest.setDefaultCustomFields(issuesService.getDefaultCustomFields(syncRequest.getProjectId()));
}
issuesService.syncThirdPartyAllIssues(syncRequest, project);
}
}
} catch (Exception e) {
issuesService.deleteSyncKey(syncRequest.getProjectId());
MSException.throwException(e);
}
}
/**
* 非xpack用户
* @param projectId 项目ID
*/
public void syncIssues(String projectId) {
try {
if (StringUtils.isNotBlank(projectId)) {
String syncValue = issuesService.getSyncKey(projectId);
if (StringUtils.isEmpty(syncValue)) {
issuesService.setSyncKey(projectId);
Project project = baseProjectService.getProjectById(projectId);
List<IssuesDao> issues = extIssuesMapper.getIssueForSync(projectId, project.getPlatform());
if (CollectionUtils.isEmpty(issues)) {
issuesService.deleteSyncKey(projectId);
} else {
IssuesRequest issuesRequest = new IssuesRequest();
issuesRequest.setProjectId(projectId);
issuesRequest.setWorkspaceId(project.getWorkspaceId());
issuesRequest.setDefaultCustomFields(issuesService.getDefaultCustomField(project));
issuesService.syncThirdPartyIssues(issues, issuesRequest, project);
}
}
}
} catch (Exception e) {
issuesService.deleteSyncKey(projectId);
MSException.throwException(e);
}
}
}

View File

@ -598,43 +598,38 @@ export default {
"createTime": data.createTime.getTime(), "createTime": data.createTime.getTime(),
"pre": data.preValue "pre": data.preValue
} }
syncAllIssues(param) syncIssues()
.then(() => { .then(() => {
checkSyncIssues(this.loading, false, (errorData) => { this.repeatCheckSyncRes();
this.loading = false; }).catch(() => {
this.syncDisable = false; this.resetSyncParam();
if (errorData.syncResult && errorData.syncResult !== '') { });
this.$error(errorData.syncResult, false);
} else {
this.$success(this.$t('test_track.issue.sync_complete'), false);
this.getIssues();
}
});
})
.catch(() => {
this.loading = false;
this.syncDisable = false;
});
}, },
syncIssues() { syncIssues() {
this.loading = true; this.loading = true;
this.syncDisable = false; this.syncDisable = true;
syncIssues() syncIssues()
.then(() => { .then(() => {
checkSyncIssues(this.loading, false, (errorData) => { this.repeatCheckSyncRes();
this.loading = false;
this.syncDisable = false;
if (errorData.syncResult && errorData.syncResult !== '') {
this.$error(errorData.syncResult, false);
} else {
this.$success(this.$t('test_track.issue.sync_complete'), false);
this.getIssues();
}
});
}).catch(() => { }).catch(() => {
this.loading = false; this.resetSyncParam();
this.syncDisable = false; });
}); },
repeatCheckSyncRes() {
checkSyncIssues(this.loading, false, (errorData) => {
this.loading = false;
this.syncDisable = false;
if (errorData.syncResult && errorData.syncResult !== '') {
this.$error(errorData.syncResult, false);
} else {
this.$success(this.$t('test_track.issue.sync_complete'), false);
this.getIssues();
}
});
},
resetSyncParam() {
this.loading = false;
this.syncDisable = false;
}, },
editParam() { editParam() {
let id = this.$route.query.id; let id = this.$route.query.id;