稳定组成这个文件优化

This commit is contained in:
super
2026-05-02 16:40:13 +08:00
parent 9d4810eace
commit f46c231323
3 changed files with 50 additions and 6 deletions

View File

@@ -86,6 +86,8 @@ public class AppearancePatentTaskService {
private static final String STATUS_SUCCESS = "SUCCESS";
private static final String STATUS_FAILED = "FAILED";
private static final String CONTENT_TYPE_XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
private static final int RESULT_ROWS_READ_RETRY_LIMIT = 3;
private static final long RESULT_ROWS_READ_RETRY_DELAY_MS = 500L;
private static final List<String> RESULT_HEADERS = List.of(
"id",
"asin",
@@ -759,12 +761,17 @@ public class AppearancePatentTaskService {
}
String payloadJson = writeJson(rows == null ? List.of() : rows, "结果序列化失败");
payloadJson = writeJson(new ArrayList<>(persistedRows.values()), "appearance patent chunk payload merge failed");
String storedPayload = transientPayloadStorageService.storeChunkPayload(MODULE_TYPE, taskId, scopeHash, chunkIndex, payloadJson);
transientPayloadStorageService.deleteReplacedPayloadIfNeeded(chunk.getPayloadJson(), storedPayload);
String oldPayload = chunk.getPayloadJson();
String storedPayload = transientPayloadStorageService.storeChunkPayloadVersioned(MODULE_TYPE, taskId, scopeHash, chunkIndex, payloadJson);
chunk.setPayloadJson(storedPayload);
chunk.setPayloadHash(DigestUtil.sha256Hex(payloadJson));
chunk.setUpdatedAt(LocalDateTime.now());
taskChunkMapper.updateById(chunk);
int updated = taskChunkMapper.updateById(chunk);
if (updated <= 0) {
transientPayloadStorageService.deletePayloadIfPresent(storedPayload);
throw new IllegalStateException("appearance patent chunk payload update failed");
}
transientPayloadStorageService.deleteReplacedPayloadIfNeeded(oldPayload, storedPayload);
}
private List<AppearancePatentResultRowDto> expandRows(List<AppearancePatentResultRowDto> representatives,
@@ -1122,7 +1129,7 @@ public class AppearancePatentTaskService {
private void assembleResultWorkbook(FileTaskEntity task, FileResultEntity result) {
AppearancePatentParsedPayloadDto parsed = readParsedPayload(task);
Map<String, AppearancePatentResultRowDto> resultMap = loadPersistedResultRows(task.getId());
Map<String, AppearancePatentResultRowDto> resultMap = loadPersistedResultRowsWithRetry(task.getId(), parsed.getAllItems().size());
long resolvedRows = parsed.getAllItems().stream()
.filter(row -> findResultRow(row, resultMap) != null || findResultRowByAsin(row.getAsin(), resultMap) != null)
.count();
@@ -1131,6 +1138,9 @@ public class AppearancePatentTaskService {
.count();
log.info("[appearance-patent] assemble workbook taskId={} parsedRows={} resultRows={} resolvedRows={} reasonRows={}",
task.getId(), parsed.getAllItems().size(), resultMap.size(), resolvedRows, reasonRows);
if (!parsed.getAllItems().isEmpty() && resultMap.isEmpty()) {
throw new BusinessException("外观专利检测结果为空,请稍后重试生成结果文件");
}
File outputDir = new File(storageProperties.getLocalTempDir(), "appearance-patent-result");
if (!outputDir.exists() && !outputDir.mkdirs()) {
throw new BusinessException("创建结果目录失败");
@@ -1164,6 +1174,33 @@ public class AppearancePatentTaskService {
return result;
}
private Map<String, AppearancePatentResultRowDto> loadPersistedResultRowsWithRetry(Long taskId, int expectedParsedRows) {
Map<String, AppearancePatentResultRowDto> result = loadPersistedResultRows(taskId);
if (expectedParsedRows <= 0 || !result.isEmpty()) {
return result;
}
for (int attempt = 1; attempt <= RESULT_ROWS_READ_RETRY_LIMIT && result.isEmpty(); attempt++) {
sleepBeforeResultRowsRetry(attempt);
result = loadPersistedResultRows(taskId);
if (!result.isEmpty()) {
log.info("[appearance-patent] result rows recovered after retry taskId={} attempt={} rows={}",
taskId, attempt, result.size());
return result;
}
log.warn("[appearance-patent] result rows still empty after retry taskId={} attempt={}/{}",
taskId, attempt, RESULT_ROWS_READ_RETRY_LIMIT);
}
return result;
}
private void sleepBeforeResultRowsRetry(int attempt) {
try {
Thread.sleep(RESULT_ROWS_READ_RETRY_DELAY_MS * attempt);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
private void writeResultWorkbook(File xlsx, AppearancePatentParsedPayloadDto parsed, Map<String, AppearancePatentResultRowDto> resultMap) {
try (SXSSFWorkbook workbook = new SXSSFWorkbook(200); FileOutputStream fos = new FileOutputStream(xlsx)) {
Sheet sheet = workbook.createSheet("外观专利检测结果");

View File

@@ -55,6 +55,13 @@ public class TransientPayloadStorageService {
return store("task-chunk", moduleType, taskId, scopeHash, entryKey, content, true);
}
public String storeChunkPayloadVersioned(String moduleType, Long taskId, String scopeHash, Integer chunkIndex, String content) {
String entryKey = chunkIndex == null
? UUID.randomUUID().toString()
: "chunk-" + chunkIndex + "-" + UUID.randomUUID();
return store("task-chunk", moduleType, taskId, scopeHash, entryKey, content, true);
}
public String resolvePayload(String value, String errorMessage) {
String pointer = extractPointer(value);
if (pointer == null) {