fix(aihr): clean up orphaned knowledge uploads

This commit is contained in:
2026-07-14 21:43:27 +08:00
parent 30a473b365
commit 04b9b1bb96
4 changed files with 43 additions and 6 deletions
@@ -763,9 +763,14 @@ public class AihrSopSeedService {
docId = reuseDuplicateAttach(hit, config.knowledgeId(), fileName);
remark = "duplicate:" + hit.matchType() + ":" + insight.classifiedBy();
} else {
SysOssVo oss = ossUploader.get();
ossId = oss.getOssId();
docId = upsertAttach(config.knowledgeId(), ossId, fileName);
SysOssVo uploadedOss = ossUploader.get();
ossId = uploadedOss.getOssId();
try {
docId = upsertAttach(config.knowledgeId(), ossId, fileName);
} catch (RuntimeException error) {
deleteUploadedOssQuietly(uploadedOss);
throw error;
}
remark = "oss-upload:" + insight.classifiedBy();
}
try {
@@ -804,8 +809,14 @@ public class AihrSopSeedService {
String defaultName = video ? "培训视频" : "图片素材";
String knowledgeName = isAutoCategory(category) || category == null || category.isBlank() ? defaultName : cleanCategory(category);
KnowledgeConfig config = knowledgeConfig(knowledgeName);
SysOssVo oss = ossUploader.get();
String docId = upsertAttach(config.knowledgeId(), oss.getOssId(), fileName);
SysOssVo uploadedOss = ossUploader.get();
String docId;
try {
docId = upsertAttach(config.knowledgeId(), uploadedOss.getOssId(), fileName);
} catch (RuntimeException error) {
deleteUploadedOssQuietly(uploadedOss);
throw error;
}
markAttachStatus(config.knowledgeId(), docId, 0, video ? "pending-transcribe" : "pending-ocr");
String hint;
if (video) {
@@ -816,7 +827,18 @@ public class AihrSopSeedService {
: "未配置可用视觉模型,图片已入库标记待处理;在模型管理启用 vision/多模态 chat 模型后重新上传即可解析";
}
List<String> tags = video ? List.of("视频", "待转写") : List.of("图片", "待OCR");
return new UploadResponse(docId, oss.getOssId(), fileName, knowledgeName, 0, hint, tags, List.of());
return new UploadResponse(docId, uploadedOss.getOssId(), fileName, knowledgeName, 0, hint, tags, List.of());
}
private void deleteUploadedOssQuietly(SysOssVo oss) {
if (oss == null || oss.getOssId() == null || ossService == null) {
return;
}
try {
ossService.deleteWithValidByIds(List.of(oss.getOssId()), false);
} catch (Exception cleanupError) {
log.warn("knowledge document OSS cleanup failed ossId={}", oss.getOssId(), cleanupError);
}
}
private DocumentInsight documentInsight(String fileName, String content, String requestedCategory) {
@@ -143,6 +143,19 @@ public class AihrSopSeedServiceTest {
assertTrue(code.contains("!modelService.visionAllowed()"));
}
@Test
@Tag("dev")
public void documentUploadCleansNewOssWhenAttachWriteFails() throws Exception {
Path source = Path.of("src/main/java/org/dromara/aihr/service/AihrSopSeedService.java");
if (!Files.exists(source)) {
source = Path.of("ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java");
}
String code = Files.readString(source);
assertTrue(code.contains("deleteUploadedOssQuietly(uploadedOss)"));
assertTrue(code.contains("private void deleteUploadedOssQuietly(SysOssVo oss)"));
}
@Test
@Tag("dev")
public void disabledVisionGateStopsBeforeDatabaseLookup() throws Exception {