Repository: apache/seatunnel (Java)

Issue:
[Bug] [clickhouse] CK连接器任务抽取完毕后无法正常停止
### Search before asking

- [X] I had searched in the [issues](https://github.com/apache/seatunnel/issues?q=is%3Aissue+label%3A%22bug%22) and found no similar issues.


### What happened

当我通过clickhouse连接器抽取数据的时候，觉得速度比较慢，想调整并行度（虽然看到官网提示clickhouse连接器目前不支持并行），把parallelism 调整为2，这个时候当任务抽取完毕的时候，该任务并不会停止
已经验证过，必现，当我把并行度改为1的时候就没问题

虽然不支持并行度，但是期望调整 parallelism 参数并不会影响任务的正常结束
另外期望能开发该连接器，使其支持并行
可以提供思路，我来改

### SeaTunnel Version

2.3.7

### SeaTunnel Config

```conf
env {
  parallelism = 2
  job.mode = "BATCH"
}


source{
    Clickhouse {
    host = ""
    database = "fdc"
    sql = "select * from fdc.trace_data WHERE traceTime > '2024-10-24 04:00:00' and traceTime < '2024-10-24 04:00:20'"
    username = "reader"
    password = "reader@123"
    server_time_zone = "UTC"
    result_table_name = "fdc.trace_data"
    clickhouse.config = {
	  "max_memory_usage": "128000000000",
	  "max_bytes_before_external_group_by": "50000000000",
      "socket_timeout": "300000"
    }
  }
}


sink {
    jdbc {
        url = "jdbc:oceanbase:///ods"
        driver = "com.oceanbase.jdbc.Driver"
        user = "root"
        password = "Bh%Yac{C9l-~#?~dq[}bSQO5ng8Rr?w"
        compatible_mode = "mysql"
        generate_sink_sql = true
        database = ods
        table = trace_data
        data_save_mode = APPEND_DATA
    }
}
```


### Running Command

```shell
./bin/seatunnel.sh --config job/ck2ob.config -e local
```


### Error Exception

```log
任务抽取完毕，但是停不下来
```


### Zeta or Flink or Spark Version

zeta

### Java or Scala Version

java

### Screenshots

![119180a7b9e22a7afeadc960f80a42a](https://github.com/user-attachments/assets/627736b7-0eab-47bc-a40c-8d2eb0539874)


### Are you willing to submit PR?

- [X] Yes I am willing to submit a PR!

### Code of Conduct

- [X] I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct)




Fix (patch):
diff --git a/seatunnel-connectors-v2/connector-clickhouse/src/main/java/org/apache/seatunnel/connectors/seatunnel/clickhouse/source/ClickhouseSourceReader.java b/seatunnel-connectors-v2/connector-clickhouse/src/main/java/org/apache/seatunnel/connectors/seatunnel/clickhouse/source/ClickhouseSourceReader.java
index 591334d9722..3ad0ec041e6 100644
--- a/seatunnel-connectors-v2/connector-clickhouse/src/main/java/org/apache/seatunnel/connectors/seatunnel/clickhouse/source/ClickhouseSourceReader.java
+++ b/seatunnel-connectors-v2/connector-clickhouse/src/main/java/org/apache/seatunnel/connectors/seatunnel/clickhouse/source/ClickhouseSourceReader.java
@@ -17,6 +17,7 @@
 
 package org.apache.seatunnel.connectors.seatunnel.clickhouse.source;
 
+import org.apache.seatunnel.api.source.Boundedness;
 import org.apache.seatunnel.api.source.Collector;
 import org.apache.seatunnel.api.source.SourceReader;
 import org.apache.seatunnel.api.table.type.SeaTunnelRow;
@@ -28,6 +29,7 @@
 import com.clickhouse.client.ClickHouseNode;
 import com.clickhouse.client.ClickHouseRequest;
 import com.clickhouse.client.ClickHouseResponse;
+import lombok.extern.slf4j.Slf4j;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -35,6 +37,7 @@
 import java.util.List;
 import java.util.Random;
 
+@Slf4j
 public class ClickhouseSourceReader implements SourceReader<SeaTunnelRow, ClickhouseSourceSplit> {
 
     private final List<ClickHouseNode> servers;
@@ -43,6 +46,7 @@ public class ClickhouseSourceReader implements SourceReader<SeaTunnelRow, Clickh
     private final SourceReader.Context readerContext;
     private ClickHouseRequest<?> request;
     private final String sql;
+    private volatile boolean noMoreSplit;
 
     private final List<ClickhouseSourceSplit> splits;
 
@@ -75,31 +79,43 @@ public void close() throws IOException {
 
     @Override
     public void pollNext(Collector<SeaTunnelRow> output) throws Exception {
-        if (!splits.isEmpty()) {
-            try (ClickHouseResponse response = this.request.query(sql).executeAndWait()) {
-                response.stream()
-                        .forEach(
-                                record -> {
-                                    Object[] values =
-                                            new Object[this.rowTypeInfo.getFieldNames().length];
-                                    for (int i = 0; i < record.size(); i++) {
-                                        if (record.getValue(i).isNullOrEmpty()) {
-                                            values[i] = null;
-                                        } else {
-                                            values[i] =
-                                                    TypeConvertUtil.valueUnwrap(
-                                                            this.rowTypeInfo.getFieldType(i),
-                                                            record.getValue(i));
+        synchronized (output.getCheckpointLock()) {
+            if (!splits.isEmpty()) {
+                try (ClickHouseResponse response = this.request.query(sql).executeAndWait()) {
+                    response.stream()
+                            .forEach(
+                                    record -> {
+                                        Object[] values =
+                                                new Object[this.rowTypeInfo.getFieldNames().length];
+                                        for (int i = 0; i < record.size(); i++) {
+                                            if (record.getValue(i).isNullOrEmpty()) {
+                                                values[i] = null;
+                                            } else {
+                                                values[i] =
+                                                        TypeConvertUtil.valueUnwrap(
+                                                                this.rowTypeInfo.getFieldType(i),
+                                                                record.getValue(i));
+                                            }
                                         }
-                                    }
-                                    output.collect(new SeaTunnelRow(values));
-                                });
+                                        output.collect(new SeaTunnelRow(values));
+                                    });
+                }
+                signalNoMoreElement();
+            }
+            if (noMoreSplit
+                    && splits.isEmpty()
+                    && Boundedness.BOUNDED.equals(readerContext.getBoundedness())) {
+                signalNoMoreElement();
             }
-            this.readerContext.signalNoMoreElement();
-            this.splits.clear();
         }
     }
 
+    private void signalNoMoreElement() {
+        log.info("Closed the bounded ClickHouse source");
+        this.readerContext.signalNoMoreElement();
+        this.splits.clear();
+    }
+
     @Override
     public List<ClickhouseSourceSplit> snapshotState(long checkpointId) throws Exception {
         return Collections.emptyList();
@@ -111,7 +127,9 @@ public void addSplits(List<ClickhouseSourceSplit> splits) {
     }
 
     @Override
-    public void handleNoMoreSplits() {}
+    public void handleNoMoreSplits() {
+        noMoreSplit = true;
+    }
 
     @Override
     public void notifyCheckpointComplete(long checkpointId) throws Exception {}
diff --git a/seatunnel-connectors-v2/connector-clickhouse/src/main/java/org/apache/seatunnel/connectors/seatunnel/clickhouse/source/ClickhouseSourceSplitEnumerator.java b/seatunnel-connectors-v2/connector-clickhouse/src/main/java/org/apache/seatunnel/connectors/seatunnel/clickhouse/source/ClickhouseSourceSplitEnumerator.java
index c0eb4b6c706..f3c1bd0c47b 100644
--- a/seatunnel-connectors-v2/connector-clickhouse/src/main/java/org/apache/seatunnel/connectors/seatunnel/clickhouse/source/ClickhouseSourceSplitEnumerator.java
+++ b/seatunnel-connectors-v2/connector-clickhouse/src/main/java/org/apache/seatunnel/connectors/seatunnel/clickhouse/source/ClickhouseSourceSplitEnumerator.java
@@ -78,6 +78,7 @@ public void registerReader(int subtaskId) {
             assigned = subtaskId;
             context.assignSplit(subtaskId, new ClickhouseSourceSplit());
         }
+        context.signalNoMoreSplits(subtaskId);
     }
 
     @Override
diff --git a/seatunnel-engine/seatunnel-engine-common/src/main/resources/seatunnel.yaml b/seatunnel-engine/seatunnel-engine-common/src/main/resources/seatunnel.yaml
index c9bb71ecc07..8c5a136d1b0 100644
--- a/seatunnel-engine/seatunnel-engine-common/src/main/resources/seatunnel.yaml
+++ b/seatunnel-engine/seatunnel-engine-common/src/main/resources/seatunnel.yaml
@@ -20,6 +20,7 @@ seatunnel:
         backup-count: 1
         queue-type: blockingqueue
         print-execution-info-interval: 60
+        print-job-metrics-info-interval: 60
         slot-service:
             dynamic-slot: true
         checkpoint: