[DAT] 重试时根据上一次执行步骤来决定

This commit is contained in:
liu.zixi
2025-10-29 17:43:18 +08:00
parent ad981eb49d
commit 8188810f5d
3 changed files with 142 additions and 13 deletions

View File

@@ -1,5 +1,6 @@
package com.xboe.module.boecase.service;
import com.xboe.module.boecase.entity.CaseDocumentLog;
import com.xboe.module.boecase.entity.Cases;
import org.springframework.transaction.annotation.Transactional;
@@ -46,7 +47,7 @@ public interface ICaseKnowledgeService {
* @param caseId 案例ID
* @return 是否成功
*/
boolean updateCaseDocument(String caseId);
boolean retryCaseDocument(String caseId, CaseDocumentLog originalLog);
/**
* 更新案例文档

View File

@@ -1,7 +1,6 @@
package com.xboe.module.boecase.service.impl;
import com.xboe.common.utils.StringUtil;
import com.xboe.common.utils.IDGenerator;
import com.xboe.common.OrderCondition;
import com.xboe.common.PageList;
import com.xboe.core.orm.FieldFilters;
@@ -189,7 +188,7 @@ public class CaseDocumentLogServiceImpl implements ICaseDocumentLogService {
String optType = originalLog.getOptType();
String caseId = originalLog.getCaseId();
aiDocExecutor.execute(() -> executeRetryLogic(optType, caseId));
aiDocExecutor.execute(() -> executeRetryLogic(optType, caseId, originalLog));
// 立即返回true表示重试请求已接受具体结果通过日志异步处理
return true;
@@ -200,7 +199,7 @@ public class CaseDocumentLogServiceImpl implements ICaseDocumentLogService {
* @param optType 操作类型
* @param caseId 案例ID
*/
private void executeRetryLogic(String optType, String caseId) {
private void executeRetryLogic(String optType, String caseId, CaseDocumentLog originalLog) {
boolean retrySuccess = false;
try {
@@ -223,7 +222,7 @@ public class CaseDocumentLogServiceImpl implements ICaseDocumentLogService {
} else if (CaseDocumentLogOptTypeEnum.UPDATE.getCode().equals(optType)) {
// 更新案例文档
retrySuccess = caseKnowledgeService.updateCaseDocument(caseId);
retrySuccess = caseKnowledgeService.retryCaseDocument(caseId, originalLog);
log.info("[异步任务] 执行更新案例文档重试caseId: {}, 结果: {}", caseId, retrySuccess);
} else {

View File

@@ -23,12 +23,11 @@ import com.xboe.module.boecase.properties.CaseAiProperties;
import com.xboe.module.boecase.service.IAiAccessTokenService;
import com.xboe.module.boecase.service.ICaseKnowledgeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.*;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
@@ -42,12 +41,9 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 案例-知识库Service实现类
@@ -377,15 +373,148 @@ public class CaseKnowledgeServiceImpl implements ICaseKnowledgeService {
}
@Override
public boolean updateCaseDocument(String caseId) {
public boolean retryCaseDocument(String caseId, CaseDocumentLog originalLog) {
if (StringUtil.isBlank(caseId)) {
log.error("更新案例文档失败案例ID不能为空");
return false;
}
// 1. 查询案例信息
Cases caseEntity = casesDao.findOne(FieldFilters.eq("id", caseId));
return updateCaseDocument(caseEntity);
Cases cases = casesDao.findOne(FieldFilters.eq("id", caseId));
// 2. 查询待重试内容
if (StringUtils.equals(originalLog.getRequestUrl(), CaseAiConstants.CASE_DOC_DELETE_INTERFACE_NAME)) {
return updateCaseDocument(cases);
}
// 如果需要上传
JSONObject requestBody = new JSONObject();
String userId = getCurrentUserId();
requestBody.put("userId", userId);
requestBody.put("kId", caseAiProperties.getCaseKnowledgeId());
requestBody.put("parseType", "AUTO");
// 2. 检查文件路径
if (StringUtil.isBlank(cases.getFilePath())) {
log.error("上传案例文档失败案例文件路径为空caseId: {}", caseId);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), "上传案例文档失败,案例文件路径为空",
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
return false;
}
String savePath = fileUploader.getSavePath();
String filePath = savePath + cases.getFilePath();
File file = new File(filePath);
if (!file.exists()) {
log.error("上传案例文档失败案例文件不存在filePath: {}", filePath);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), "上传案例文档失败案例文件不存在filePath: " + filePath,
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
return false;
}
// 4. 构建上传参数
String fileName = cases.getFileName();
if (StringUtil.isBlank(fileName)) {
fileName = file.getName();
}
String fileType = getFileType(fileName);
// 5. 重试逻辑最多3次机会
int uploadMaxRetries = 3;
// 构建multipart/form-data请求体
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addBinaryBody("file", file);
builder.addTextBody("userId", userId, ContentType.TEXT_PLAIN);
builder.addTextBody("kId", caseAiProperties.getCaseKnowledgeId(), ContentType.TEXT_PLAIN);
builder.addTextBody("fileName", fileName, ContentType.TEXT_PLAIN);
requestBody.put("fileName", fileName);
builder.addTextBody("fileType", fileType, ContentType.TEXT_PLAIN);
requestBody.put("fileType", fileType);
builder.addTextBody("parseType", "AUTO", ContentType.TEXT_PLAIN);
// 由于接口权限,目前采用不回调,而是通过批处理的方式,处理文件状态
if (caseAiProperties.isFileUploadUseCallback()) {
builder.addTextBody("callbackUrl", caseAiProperties.getFileUploadCallbackUrl(), ContentType.TEXT_PLAIN);
requestBody.put("callbackUrl", caseAiProperties.getFileUploadCallbackUrl());
}
String uploadUrl = caseAiProperties.getBaseUrl() + "/apigateway/knowledge/v1/file/upload";
// 3. 获取access_token
String accessToken = aiAccessTokenService.getAccessToken();
if (StringUtil.isBlank(accessToken)) {
log.error("上传案例文档失败获取access_token失败");
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), "上传案例文档失败获取access_token失败",
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
return false;
}
for (int attempt = 1; attempt <= uploadMaxRetries; attempt++) {
log.info("上传案例文档第{}次尝试caseId: {}", attempt, caseId);
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(uploadUrl);
httpPost.setHeader("X-AI-ApiCode", caseAiProperties.getAiApiCode());
httpPost.setHeader("access_token", accessToken);
HttpEntity multipart = builder.build();
httpPost.setEntity(multipart);
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
if (statusCode == 200) {
JSONObject result = JSON.parseObject(responseBody);
if (result.getBooleanValue("success")) {
// 业务处理成功
JSONObject data = result.getJSONObject("data");
String taskId = data.getString("taskId");
// 保存成功的CaseDocumentLog记录
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), responseBody,
CaseDocumentLogRunStatusEnum.RUNNING.getCode(), null, null, taskId);
log.info("上传案例文档成功,等待文档状态变更. caseId: {}, taskId: {}, 尝试次数: {}", caseId, taskId, attempt);
return true;
} else {
// 业务处理失败,不重试
log.error("上传案例文档业务处理失败不重试response: {}", responseBody);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), responseBody,
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.SUCCESS.getCode(), CaseDocumentLogCaseStatusEnum.FAILED.getCode(), null);
return false;
}
} else {
// 接口调用失败
log.error("上传案例文档接口调用失败,第{}次尝试status: {}, response: {}", attempt, statusCode, responseBody);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), responseBody,
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
if (attempt == uploadMaxRetries) {
// 最后一次尝试仍然失败
return false;
}
// 继续下一次重试
}
}
} catch (Exception e) {
// 接口调用异常
log.error("上传案例文档接口调用异常,第{}次尝试", attempt, e);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), "接口调用异常: " + e.getMessage(),
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
if (attempt == uploadMaxRetries) {
// 最后一次尝试仍然异常
log.error("上传案例文档最终失败,已重试{}次", uploadMaxRetries);
return false;
}
// 继续下一次重试
}
}
return false;
}
@Override