From 4327b94fd0a25192c396e83d0cafee76d28e3183 Mon Sep 17 00:00:00 2001 From: mangmang <362165265@qq.com> Date: Sun, 19 Jul 2026 22:17:35 +0800 Subject: [PATCH] Fix expired ingest task stuck state --- .../com/music/controller/IngestController.java | 3 ++- .../service/ProgressMessageMappingTest.java | 16 ++++++++++++++++ frontend/src/components/IngestTab.vue | 9 ++++++--- frontend/src/composables/useWebSocket.ts | 2 ++ 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/com/music/controller/IngestController.java b/backend/src/main/java/com/music/controller/IngestController.java index 52f5391..03544ea 100644 --- a/backend/src/main/java/com/music/controller/IngestController.java +++ b/backend/src/main/java/com/music/controller/IngestController.java @@ -81,7 +81,8 @@ public class IngestController { public Result statusById(@PathVariable("taskId") String taskId) { ProgressMessage pm = progressStore.get(taskId); if (pm == null) { - return Result.success(new IngestStatusResponse(taskId, running.get(), false, + boolean isRunning = running.get(); + return Result.success(new IngestStatusResponse(taskId, isRunning, !isRunning, 0, 0, 0, 0, 0, 0, 0, 0, "未找到任务或已过期")); } diff --git a/backend/src/test/java/com/music/service/ProgressMessageMappingTest.java b/backend/src/test/java/com/music/service/ProgressMessageMappingTest.java index d7d9688..fdd161e 100644 --- a/backend/src/test/java/com/music/service/ProgressMessageMappingTest.java +++ b/backend/src/test/java/com/music/service/ProgressMessageMappingTest.java @@ -8,6 +8,7 @@ import java.lang.reflect.Method; import java.util.concurrent.atomic.AtomicBoolean; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -159,4 +160,19 @@ class ProgressMessageMappingTest { com.music.common.Result result = controller.start(new com.music.dto.IngestRequest()); assertTrue(result.getCode() == 0); } + + @Test + void ingestControllerTreatsMissingStoppedTaskAsTerminal() throws Exception { + ConfigService cfgService = mock(ConfigService.class); + ProgressStore store = new ProgressStore(); + com.music.controller.IngestController controller = new com.music.controller.IngestController( + mock(IngestService.class), store, cfgService); + + com.music.common.Result result = + controller.statusById("expired-task"); + + assertFalse(result.getData().isRunning()); + assertTrue(result.getData().isCompleted()); + assertEquals("未找到任务或已过期", result.getData().getMessage()); + } } diff --git a/frontend/src/components/IngestTab.vue b/frontend/src/components/IngestTab.vue index 426e9cc..d4b1694 100644 --- a/frontend/src/components/IngestTab.vue +++ b/frontend/src/components/IngestTab.vue @@ -532,8 +532,9 @@ function handleProgressMessage(msg: ProgressMessage) { Object.assign(progress, msg); recordActivity(msg); - submitting.value = !msg.completed && (submitting.value || !!msg.taskId); - if (msg.completed) { + if (typeof msg.running === 'boolean') { + submitting.value = msg.running; + } else if (msg.completed) { submitting.value = false; } @@ -558,6 +559,7 @@ function statusToProgress(resp: IngestStatusResponse): ProgressMessage { currentFile: '', message: resp.message, completed: resp.completed, + running: resp.running, ingestedFiles: resp.ingestedFiles, duplicateFiles: resp.duplicateFiles, missingMetadataFiles: resp.missingMetadataFiles, @@ -575,8 +577,9 @@ function startPolling() { const resp = await getIngestStatus(taskId.value); if (resp) { handleProgressMessage(statusToProgress(resp)); - if (resp.completed) { + if (resp.completed || !resp.running) { stopPolling(); + wsDisconnect(); } } } catch { diff --git a/frontend/src/composables/useWebSocket.ts b/frontend/src/composables/useWebSocket.ts index 257e798..4eb6e53 100644 --- a/frontend/src/composables/useWebSocket.ts +++ b/frontend/src/composables/useWebSocket.ts @@ -12,6 +12,8 @@ export interface ProgressMessage { currentFile: string; message: string; completed: boolean; + /** REST 状态查询提供;WebSocket 进度消息通常不包含此字段。 */ + running?: boolean; duplicateGroups?: number; movedFiles?: number; organizedFiles?: number;