From a9bf018081b5718ddbf8c29cb17d5e11c07b6bb1 Mon Sep 17 00:00:00 2001 From: yujun Date: Thu, 30 Jul 2026 14:59:48 +0800 Subject: [PATCH] [fix](job scheduler) Record task finish time on execution failure (#66232) ### What problem does this PR solve? When a task fails through the execution exception path, `AbstractTask.runTask()` calls the no-argument `onFail()`, which marked the task FAILED without recording `finishTimeMs`. MTMV failed refresh tasks therefore exposed an empty FinishTime and could not calculate DurationMs. relate PR: #27703 ### What changes were made? - Record `finishTimeMs` when `AbstractTask.onFail()` transitions a task to FAILED. - Add a regression unit test covering the `runTask()` exception path and preserving the error message. ### Testing - `AbstractJobStatusTest`: 13 tests passed. --- .../apache/doris/job/task/AbstractTask.java | 1 + .../doris/job/base/AbstractJobStatusTest.java | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/fe/fe-core/src/main/java/org/apache/doris/job/task/AbstractTask.java b/fe/fe-core/src/main/java/org/apache/doris/job/task/AbstractTask.java index 4e2ac653cf700f..9cf70edb6556f8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/job/task/AbstractTask.java +++ b/fe/fe-core/src/main/java/org/apache/doris/job/task/AbstractTask.java @@ -71,6 +71,7 @@ public boolean onFail() throws JobException { return false; } status = TaskStatus.FAILED; + setFinishTimeMs(System.currentTimeMillis()); if (!isCallable()) { return false; } diff --git a/fe/fe-core/src/test/java/org/apache/doris/job/base/AbstractJobStatusTest.java b/fe/fe-core/src/test/java/org/apache/doris/job/base/AbstractJobStatusTest.java index faf39164fc3800..588aae4c0ca9af 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/job/base/AbstractJobStatusTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/job/base/AbstractJobStatusTest.java @@ -66,6 +66,18 @@ boolean cancelLogicCalled() { } } + private static class FailingTask extends DummyTask { + FailingTask(long taskId) { + super(taskId); + setJobId(1L); + } + + @Override + public void run() throws JobException { + throw new JobException("task failed"); + } + } + private static class DummyJob extends AbstractJob { private final List history = new ArrayList<>(); @@ -131,6 +143,17 @@ void testPendingFromPaused() throws Exception { Assertions.assertEquals(JobStatus.PENDING, job.getJobStatus()); } + @Test + void testTaskFailureSetsFinishTime() throws Exception { + FailingTask task = new FailingTask(100L); + + task.runTask(); + + Assertions.assertEquals(TaskStatus.FAILED, task.getStatus()); + Assertions.assertNotNull(task.getFinishTimeMs()); + Assertions.assertEquals("task failed", task.getErrMsg()); + } + @Test void testPendingFromRunning() throws Exception { DummyJob job = new DummyJob(JobStatus.RUNNING);