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

davidzollo 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 d6907ad4ea [Fix][Zeta] CleanLogOperation receives jobId=0 in separated 
cluster mode (#10797)
d6907ad4ea is described below

commit d6907ad4ea94059fa970d5ee27c667564e46f581
Author: Bodhi <[email protected]>
AuthorDate: Sun Jul 19 09:58:41 2026 +0800

    [Fix][Zeta] CleanLogOperation receives jobId=0 in separated cluster mode 
(#10797)
    
    Co-authored-by: huyangbo <[email protected]>
---
 .../telemetry/log/TaskLogManagerService.java       |  9 +--
 .../telemetry/log/operation/CleanLogOperation.java | 16 +++++
 .../telemetry/log/TaskLogManagerServiceTest.java   | 73 ++++++++++++++++++++++
 .../CleanLogOperationSerializationTest.java        | 64 +++++++++++++++++++
 4 files changed, 158 insertions(+), 4 deletions(-)

diff --git 
a/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/telemetry/log/TaskLogManagerService.java
 
b/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/telemetry/log/TaskLogManagerService.java
index e90ab0c80c..94534ef1e4 100644
--- 
a/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/telemetry/log/TaskLogManagerService.java
+++ 
b/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/telemetry/log/TaskLogManagerService.java
@@ -52,16 +52,17 @@ public class TaskLogManagerService {
 
     /** Removes local log files whose names still include the target job id. */
     public void clean(long jobId) {
-        log.info("Cleaning logs for jobId: {} , path : {}", jobId, path);
-        if (path == null) {
+        if (path == null || jobId <= 0) {
             return;
         }
         String[] logFiles = getLogFiles(jobId, path);
         for (String logFile : logFiles) {
+            String logPath = path + "/" + logFile;
+            log.info("Cleaning logs for jobId: {} , path : {}", jobId, 
logPath);
             try {
-                Files.delete(Paths.get(path + "/" + logFile));
+                Files.delete(Paths.get(logPath));
             } catch (IOException e) {
-                log.warn("Failed to delete log file: {}", logFile, e);
+                log.warn("Failed to delete log file: {}", logPath, e);
             }
         }
     }
diff --git 
a/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/telemetry/log/operation/CleanLogOperation.java
 
b/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/telemetry/log/operation/CleanLogOperation.java
index 2f5f215d80..5257e1cbe8 100644
--- 
a/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/telemetry/log/operation/CleanLogOperation.java
+++ 
b/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/telemetry/log/operation/CleanLogOperation.java
@@ -22,8 +22,12 @@ import 
org.apache.seatunnel.engine.server.serializable.TaskDataSerializerHook;
 import org.apache.seatunnel.engine.server.task.operation.TracingOperation;
 import org.apache.seatunnel.engine.server.telemetry.log.TaskLogManagerService;
 
+import com.hazelcast.nio.ObjectDataInput;
+import com.hazelcast.nio.ObjectDataOutput;
 import com.hazelcast.nio.serialization.IdentifiedDataSerializable;
 
+import java.io.IOException;
+
 public class CleanLogOperation extends TracingOperation implements 
IdentifiedDataSerializable {
 
     private long jobId;
@@ -44,6 +48,18 @@ public class CleanLogOperation extends TracingOperation 
implements IdentifiedDat
         }
     }
 
+    @Override
+    protected void writeInternal(ObjectDataOutput out) throws IOException {
+        super.writeInternal(out);
+        out.writeLong(jobId);
+    }
+
+    @Override
+    protected void readInternal(ObjectDataInput in) throws IOException {
+        super.readInternal(in);
+        this.jobId = in.readLong();
+    }
+
     @Override
     public int getFactoryId() {
         return TaskDataSerializerHook.FACTORY_ID;
diff --git 
a/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/telemetry/log/TaskLogManagerServiceTest.java
 
b/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/telemetry/log/TaskLogManagerServiceTest.java
new file mode 100644
index 0000000000..26968e97cb
--- /dev/null
+++ 
b/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/telemetry/log/TaskLogManagerServiceTest.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.seatunnel.engine.server.telemetry.log;
+
+import org.apache.seatunnel.common.utils.ReflectionUtils;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class TaskLogManagerServiceTest {
+
+    @TempDir Path tempDir;
+
+    private TaskLogManagerService service;
+
+    @BeforeEach
+    void setUp() {
+        service = new TaskLogManagerService(null);
+        ReflectionUtils.setField(service, "path", tempDir.toString());
+    }
+
+    @Test
+    void testCleanDoesNothingWhenJobIdIsZero() throws IOException {
+        Path logFile = tempDir.resolve("job-1111022.log");
+        Files.write(logFile, "test log 
content".getBytes(StandardCharsets.UTF_8));
+
+        service.clean(0);
+
+        assertTrue(Files.exists(logFile), "Log file should NOT be deleted when 
jobId is 0");
+    }
+
+    @Test
+    void testCleanDeletesMatchingLogFiles() throws IOException {
+        long jobId = 12345L;
+        Path matchFile1 = tempDir.resolve("seatunnel-" + jobId + 
"-task-1.log");
+        Path matchFile2 = tempDir.resolve("worker-" + jobId + "-task-2.log");
+        Path otherFile = tempDir.resolve("seatunnel-99999-task.log");
+
+        Files.write(matchFile1, "log1".getBytes(StandardCharsets.UTF_8));
+        Files.write(matchFile2, "log2".getBytes(StandardCharsets.UTF_8));
+        Files.write(otherFile, "other".getBytes(StandardCharsets.UTF_8));
+
+        service.clean(jobId);
+
+        assertFalse(Files.exists(matchFile1), "Log file containing jobId 
should be deleted");
+        assertFalse(Files.exists(matchFile2), "Log file containing jobId 
should be deleted");
+        assertTrue(Files.exists(otherFile), "Log file not matching jobId 
should be preserved");
+    }
+}
diff --git 
a/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/telemetry/log/operation/CleanLogOperationSerializationTest.java
 
b/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/telemetry/log/operation/CleanLogOperationSerializationTest.java
new file mode 100644
index 0000000000..168b99efa4
--- /dev/null
+++ 
b/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/telemetry/log/operation/CleanLogOperationSerializationTest.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.seatunnel.engine.server.telemetry.log.operation;
+
+import org.apache.seatunnel.common.utils.ReflectionUtils;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.hazelcast.internal.serialization.Data;
+import com.hazelcast.internal.serialization.InternalSerializationService;
+import 
com.hazelcast.internal.serialization.impl.DefaultSerializationServiceBuilder;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Verifies that CleanLogOperation correctly preserves jobId through Hazelcast 
serialization
+ * round-trip (writeInternal / readInternal).
+ *
+ * <p>This is critical in split-deployment mode where the operation is 
serialized on the master node
+ * and deserialized on the worker node. Without proper 
writeInternal/readInternal, the worker
+ * receives jobId=0.
+ */
+public class CleanLogOperationSerializationTest {
+
+    private InternalSerializationService serializationService;
+
+    @BeforeEach
+    void setUp() {
+        serializationService = new 
DefaultSerializationServiceBuilder().build();
+    }
+
+    @Test
+    void testJobIdIsPreservedAfterSerialization() {
+        long expectedJobId = 123456789L;
+
+        CleanLogOperation original = new CleanLogOperation(expectedJobId);
+        Data data = serializationService.toData(original);
+
+        CleanLogOperation deserialized = serializationService.toObject(data);
+        Long jobId =
+                ReflectionUtils.getField(deserialized, "jobId")
+                        .map(field -> (long) field)
+                        .orElseThrow(
+                                () -> new RuntimeException("Failed to read 
jobId via reflection"));
+
+        assertEquals(expectedJobId, jobId);
+    }
+}

Reply via email to