This is an automated email from the ASF dual-hosted git repository.

nielifeng pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/seatunnel.git


The following commit(s) were added to refs/heads/dev by this push:
     new 229e006bd3 [Fix][Zeta] Handle missing checkpoint state during restore 
(#11565)
229e006bd3 is described below

commit 229e006bd33251304c7e5609af0b917214b0f3b4
Author: lifeng <[email protected]>
AuthorDate: Wed Jul 29 14:37:18 2026 +0800

    [Fix][Zeta] Handle missing checkpoint state during restore (#11565)
    
    Signed-off-by: lifeng <[email protected]>
---
 .../server/checkpoint/CheckpointCoordinator.java   |  4 +-
 .../checkpoint/CheckpointCoordinatorTest.java      | 58 ++++++++++++++++++++++
 2 files changed, 60 insertions(+), 2 deletions(-)

diff --git 
a/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/checkpoint/CheckpointCoordinator.java
 
b/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/checkpoint/CheckpointCoordinator.java
index ba557d3fb4..7a0fcd9983 100644
--- 
a/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/checkpoint/CheckpointCoordinator.java
+++ 
b/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/checkpoint/CheckpointCoordinator.java
@@ -1396,8 +1396,8 @@ public class CheckpointCoordinator {
         CheckpointCoordinatorStatus status =
                 (CheckpointCoordinatorStatus) 
runningJobStateIMap.get(checkpointStateImapKey);
         return 
latestCompletedCheckpoint.getCheckpointType().isFinalCheckpoint()
-                && (status.equals(CheckpointCoordinatorStatus.FINISHED)
-                        || status.equals(CheckpointCoordinatorStatus.SUSPEND))
+                && (CheckpointCoordinatorStatus.FINISHED.equals(status)
+                        || CheckpointCoordinatorStatus.SUSPEND.equals(status))
                 && !latestCompletedCheckpoint.isRestored();
     }
 
diff --git 
a/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/checkpoint/CheckpointCoordinatorTest.java
 
b/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/checkpoint/CheckpointCoordinatorTest.java
index 2e80d89d12..ff54efee8b 100644
--- 
a/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/checkpoint/CheckpointCoordinatorTest.java
+++ 
b/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/checkpoint/CheckpointCoordinatorTest.java
@@ -909,6 +909,64 @@ public class CheckpointCoordinatorTest
                 null);
     }
 
+    @Test
+    void testIsNoErrorCompletedUsesCheckpointStateMatrix() {
+        ExecutorService executorService = Executors.newCachedThreadPool();
+        try {
+            CheckpointCoordinator coordinator = 
buildMinimalCoordinator(executorService);
+            @SuppressWarnings("unchecked")
+            IMap<Object, Object> runningJobStateIMap =
+                    (IMap<Object, Object>)
+                            ReflectionUtils.getField(coordinator, 
"runningJobStateIMap")
+                                    .orElseThrow(
+                                            () ->
+                                                    new IllegalStateException(
+                                                            
"runningJobStateIMap field not found"));
+            CheckpointCoordinatorStatus[] states = {
+                null,
+                CheckpointCoordinatorStatus.RUNNING,
+                CheckpointCoordinatorStatus.CANCELED,
+                CheckpointCoordinatorStatus.FAILED,
+                CheckpointCoordinatorStatus.FINISHED,
+                CheckpointCoordinatorStatus.SUSPEND
+            };
+            for (CheckpointType checkpointType : CheckpointType.values()) {
+                for (boolean restored : new boolean[] {false, true}) {
+                    CompletedCheckpoint completedCheckpoint =
+                            new CompletedCheckpoint(
+                                    1L,
+                                    1,
+                                    1L,
+                                    System.currentTimeMillis(),
+                                    checkpointType,
+                                    System.currentTimeMillis(),
+                                    new HashMap<>(),
+                                    new HashMap<>());
+                    completedCheckpoint.setRestored(restored);
+                    ReflectionUtils.setField(
+                            coordinator, "latestCompletedCheckpoint", 
completedCheckpoint);
+
+                    for (CheckpointCoordinatorStatus status : states) {
+                        
Mockito.when(runningJobStateIMap.get(Mockito.any())).thenReturn(status);
+                        boolean expected =
+                                checkpointType.isFinalCheckpoint()
+                                        && (status == 
CheckpointCoordinatorStatus.FINISHED
+                                                || status == 
CheckpointCoordinatorStatus.SUSPEND)
+                                        && !restored;
+                        Assertions.assertEquals(
+                                expected,
+                                coordinator.isNoErrorCompleted(),
+                                String.format(
+                                        "checkpointType=%s, status=%s, 
restored=%s",
+                                        checkpointType, status, restored));
+                    }
+                }
+            }
+        } finally {
+            executorService.shutdownNow();
+        }
+    }
+
     /**
      * Regression: when {@code notifyCompleted()} fails (returns {@code 
false}), {@code
      * completePendingCheckpoint} must return immediately without decrementing 
{@code

Reply via email to