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

yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.1 by this push:
     new c3865359edc branch-4.1: [fix](job) keep Kafka metadata requests in 
compute group (#66866)
c3865359edc is described below

commit c3865359edc1645b05bf788ebd38bfd97a0a91c0
Author: hui lai <[email protected]>
AuthorDate: Thu Aug 20 09:22:11 2026 +0800

    branch-4.1: [fix](job) keep Kafka metadata requests in compute group 
(#66866)
    
    pick #66089.
---
 .../apache/doris/datasource/kafka/KafkaUtil.java   | 121 +++++++++++------
 .../load/routineload/KafkaRoutineLoadJob.java      |  33 +++--
 .../doris/datasource/kafka/KafkaUtilTest.java      | 150 +++++++++++++++++++++
 .../load/routineload/KafkaRoutineLoadJobTest.java  |  66 +++++----
 .../doris/load/routineload/RoutineLoadJobTest.java |   7 +-
 5 files changed, 300 insertions(+), 77 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/kafka/KafkaUtil.java 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/kafka/KafkaUtil.java
index 8562d0eaed3..ebdb9ea3929 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/kafka/KafkaUtil.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/kafka/KafkaUtil.java
@@ -18,6 +18,7 @@
 package org.apache.doris.datasource.kafka;
 
 import org.apache.doris.catalog.Env;
+import org.apache.doris.cloud.system.CloudSystemInfoService;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.LoadException;
 import org.apache.doris.common.Pair;
@@ -26,9 +27,11 @@ import org.apache.doris.metric.MetricRepo;
 import org.apache.doris.proto.InternalService;
 import org.apache.doris.rpc.BackendServiceProxy;
 import org.apache.doris.system.Backend;
+import org.apache.doris.system.SystemInfoService;
 import org.apache.doris.thrift.TNetworkAddress;
 import org.apache.doris.thrift.TStatusCode;
 
+import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -48,7 +51,7 @@ public class KafkaUtil {
     private static final Logger LOG = LogManager.getLogger(KafkaUtil.class);
 
     public static List<Integer> getAllKafkaPartitions(String brokerList, 
String topic,
-            Map<String, String> convertedCustomProperties) throws 
UserException {
+            Map<String, String> convertedCustomProperties, String 
computeGroupName) throws UserException {
         try {
             InternalService.PProxyRequest request = 
InternalService.PProxyRequest.newBuilder().setKafkaMetaRequest(
                     InternalService.PKafkaMetaProxyRequest.newBuilder()
@@ -61,7 +64,7 @@ public class KafkaUtil {
                                     )
                             )
             ).build();
-            return getInfoRequest(request, 
Config.max_get_kafka_meta_timeout_second)
+            return getInfoRequest(request, 
Config.max_get_kafka_meta_timeout_second, computeGroupName)
                     .getKafkaMetaResult().getPartitionIdsList();
         } catch (Exception e) {
             throw new LoadException(
@@ -73,7 +76,8 @@ public class KafkaUtil {
     // The input parameter "timestampOffsets" is <partition, timestamp>
     // Tne return value is <partition, offset>
     public static List<Pair<Integer, Long>> getOffsetsForTimes(String 
brokerList, String topic,
-            Map<String, String> convertedCustomProperties, List<Pair<Integer, 
Long>> timestampOffsets)
+            Map<String, String> convertedCustomProperties, List<Pair<Integer, 
Long>> timestampOffsets,
+            String computeGroupName)
             throws LoadException {
         if (LOG.isDebugEnabled()) {
             LOG.debug("begin to get offsets for times of topic: {}, {}", 
topic, timestampOffsets);
@@ -100,7 +104,8 @@ public class KafkaUtil {
 
             InternalService.PProxyRequest request = 
InternalService.PProxyRequest.newBuilder().setKafkaMetaRequest(
                     
metaRequestBuilder).setTimeoutSecs(Config.max_get_kafka_meta_timeout_second).build();
-            InternalService.PProxyResult result = getInfoRequest(request, 
Config.max_get_kafka_meta_timeout_second);
+            InternalService.PProxyResult result = getInfoRequest(
+                    request, Config.max_get_kafka_meta_timeout_second, 
computeGroupName);
 
             List<InternalService.PIntegerPair> pairs = 
result.getPartitionOffsets().getOffsetTimesList();
             List<Pair<Integer, Long>> partitionOffsets = Lists.newArrayList();
@@ -120,7 +125,8 @@ public class KafkaUtil {
 
     public static List<Pair<Integer, Long>> getLatestOffsets(long jobId, UUID 
taskId, String brokerList, String topic,
                                                              Map<String, 
String> convertedCustomProperties,
-                                                             List<Integer> 
partitionIds) throws LoadException {
+                                                             List<Integer> 
partitionIds, String computeGroupName)
+                                                             throws 
LoadException {
         if (LOG.isDebugEnabled()) {
             LOG.debug("begin to get latest offsets for partitions {} in topic: 
{}, task {}, job {}",
                     partitionIds, topic, taskId, jobId);
@@ -145,7 +151,8 @@ public class KafkaUtil {
             }
             InternalService.PProxyRequest request = 
InternalService.PProxyRequest.newBuilder().setKafkaMetaRequest(
                     
metaRequestBuilder).setTimeoutSecs(Config.max_get_kafka_meta_timeout_second).build();
-            InternalService.PProxyResult result = getInfoRequest(request, 
Config.max_get_kafka_meta_timeout_second);
+            InternalService.PProxyResult result = getInfoRequest(
+                    request, Config.max_get_kafka_meta_timeout_second, 
computeGroupName);
 
             List<InternalService.PIntegerPair> pairs = 
result.getPartitionOffsets().getOffsetTimesList();
             List<Pair<Integer, Long>> partitionOffsets = Lists.newArrayList();
@@ -166,7 +173,7 @@ public class KafkaUtil {
 
     public static List<Pair<Integer, Long>> getRealOffsets(String brokerList, 
String topic,
                                                              Map<String, 
String> convertedCustomProperties,
-                                                             
List<Pair<Integer, Long>> offsets)
+                                                             
List<Pair<Integer, Long>> offsets, String computeGroupName)
                                                              throws 
LoadException {
         // filter values greater than 0 as these offsets is real offset
         // only update offset like OFFSET_BEGINNING or OFFSET_END
@@ -205,7 +212,8 @@ public class KafkaUtil {
             }
             InternalService.PProxyRequest request = 
InternalService.PProxyRequest.newBuilder().setKafkaMetaRequest(
                     
metaRequestBuilder).setTimeoutSecs(Config.max_get_kafka_meta_timeout_second).build();
-            InternalService.PProxyResult result = getInfoRequest(request, 
Config.max_get_kafka_meta_timeout_second);
+            InternalService.PProxyResult result = getInfoRequest(
+                    request, Config.max_get_kafka_meta_timeout_second, 
computeGroupName);
 
             List<InternalService.PIntegerPair> pairs = 
result.getPartitionOffsets().getOffsetTimesList();
             List<Pair<Integer, Long>> partitionOffsets = Lists.newArrayList();
@@ -222,8 +230,8 @@ public class KafkaUtil {
         }
     }
 
-    private static InternalService.PProxyResult 
getInfoRequest(InternalService.PProxyRequest request, int timeout)
-                                                        throws LoadException {
+    private static InternalService.PProxyResult 
getInfoRequest(InternalService.PProxyRequest request, int timeout,
+            String computeGroupName) throws LoadException {
         long startTime = System.currentTimeMillis();
         int retryTimes = 0;
         TNetworkAddress address = null;
@@ -235,40 +243,20 @@ public class KafkaUtil {
 
         try {
             while (retryTimes < 3) {
-                List<Long> backendIds = new ArrayList<>();
-                for (Long beId : 
Env.getCurrentSystemInfo().getAllBackendIds(true)) {
-                    Backend backend = 
Env.getCurrentSystemInfo().getBackend(beId);
-                    if (isBackendAvailableForMetaRequest(backend)
-                            && !failedBeIds.contains(beId)
-                            && 
!Env.getCurrentEnv().getRoutineLoadManager().isInBlacklist(beId)) {
-                        backendIds.add(beId);
-                    }
-                }
-                // If there are no available backends, utilize the blacklist.
-                // Special scenarios include:
-                // 1. A specific job that connects to Kafka may time out for 
topic config or network error,
-                //    leaving only one backend operational.
-                // 2. If that sole backend is decommissioned, the 
aliveBackends list becomes empty.
-                // Hence, in such cases, it's essential to rely on the 
blacklist to obtain meta information.
-                if (backendIds.isEmpty()) {
-                    Map<Long, Long> blacklist = 
Env.getCurrentEnv().getRoutineLoadManager().getBlacklist();
-                    for (Long beId : blacklist.keySet()) {
-                        Backend backend = 
Env.getCurrentSystemInfo().getBackend(beId);
-                        if (isBackendAvailableForMetaRequest(backend) && 
!failedBeIds.contains(beId)) {
-                            backendIds.add(beId);
-                        } else if (backend == null) {
-                            blacklist.remove(beId);
-                            LOG.warn("remove stale backend {} from routine 
load blacklist when getting kafka meta",
-                                    beId);
-                        }
-                    }
+                List<Long> candidateBackendIds;
+                try {
+                    candidateBackendIds = 
getBackendIdsForMetaRequest(computeGroupName);
+                } catch (LoadException e) {
+                    
MetricRepo.COUNTER_ROUTINE_LOAD_GET_META_FAIL_COUNT.increase(1L);
+                    throw new 
LoadException(getInfoFailureMessage(e.getDetailMessage(), computeGroupName));
                 }
+                List<Long> backendIds = 
getAvailableBackendIdsForMetaRequest(candidateBackendIds, failedBeIds);
                 if (backendIds.isEmpty()) {
                     
MetricRepo.COUNTER_ROUTINE_LOAD_GET_META_FAIL_COUNT.increase(1L);
                     if (failedBeIds.isEmpty()) {
                         errorMsg = "no alive backends";
                     }
-                    throw new LoadException("failed to get info: " + errorMsg 
+ ",");
+                    throw new LoadException(getInfoFailureMessage(errorMsg, 
computeGroupName));
                 }
                 Collections.shuffle(backendIds);
                 long selectedBeId = backendIds.get(0);
@@ -307,7 +295,7 @@ public class KafkaUtil {
             }
 
             MetricRepo.COUNTER_ROUTINE_LOAD_GET_META_FAIL_COUNT.increase(1L);
-            throw new LoadException("failed to get info: " + errorMsg + ",");
+            throw new LoadException(getInfoFailureMessage(errorMsg, 
computeGroupName));
         } finally {
             // Ensure that not all BE added to the blacklist.
             // For single request:
@@ -329,6 +317,61 @@ public class KafkaUtil {
         }
     }
 
+    static String getInfoFailureMessage(String errorMsg, String 
computeGroupName) {
+        String computeGroupDetails = Strings.isNullOrEmpty(computeGroupName)
+                ? "" : " compute group: " + computeGroupName + ",";
+        return "failed to get info: " + errorMsg + "," + computeGroupDetails;
+    }
+
+    static List<Long> getAvailableBackendIdsForMetaRequest(
+            List<Long> candidateBackendIds, Set<Long> failedBeIds) {
+        List<Long> backendIds = new ArrayList<>();
+        for (Long beId : candidateBackendIds) {
+            Backend backend = Env.getCurrentSystemInfo().getBackend(beId);
+            if (isBackendAvailableForMetaRequest(backend)
+                    && !failedBeIds.contains(beId)
+                    && 
!Env.getCurrentEnv().getRoutineLoadManager().isInBlacklist(beId)) {
+                backendIds.add(beId);
+            }
+        }
+        // If there are no available backends, utilize the blacklist.
+        // Special scenarios include:
+        // 1. A specific job that connects to Kafka may time out for topic 
config or network error,
+        //    leaving only one backend operational.
+        // 2. If that sole backend is decommissioned, the aliveBackends list 
becomes empty.
+        // Hence, in such cases, it's essential to rely on the blacklist to 
obtain meta information.
+        if (backendIds.isEmpty()) {
+            Map<Long, Long> blacklist = 
Env.getCurrentEnv().getRoutineLoadManager().getBlacklist();
+            for (Long beId : candidateBackendIds) {
+                if (!blacklist.containsKey(beId)) {
+                    continue;
+                }
+                Backend backend = Env.getCurrentSystemInfo().getBackend(beId);
+                if (isBackendAvailableForMetaRequest(backend)
+                        && !failedBeIds.contains(beId)) {
+                    backendIds.add(beId);
+                } else if (backend == null) {
+                    blacklist.remove(beId);
+                    LOG.warn("remove stale backend {} from routine load 
blacklist when getting kafka meta", beId);
+                }
+            }
+        }
+        return backendIds;
+    }
+
+    static List<Long> getBackendIdsForMetaRequest(String computeGroupName) 
throws LoadException {
+        SystemInfoService systemInfoService = Env.getCurrentSystemInfo();
+        if (!Config.isCloudMode()) {
+            return systemInfoService.getAllBackendIds(true);
+        }
+        if (Strings.isNullOrEmpty(computeGroupName)) {
+            throw new LoadException("compute group is empty when getting kafka 
meta");
+        }
+        return ((CloudSystemInfoService) 
systemInfoService).getBackendsByClusterName(computeGroupName).stream()
+                .map(Backend::getId)
+                .collect(Collectors.toList());
+    }
+
     private static boolean isBackendAvailableForMetaRequest(Backend backend) {
         return backend != null && backend.isLoadAvailable()
                 && !backend.isDecommissioned() && !backend.isDecommissioning();
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/load/routineload/KafkaRoutineLoadJob.java
 
b/fe/fe-core/src/main/java/org/apache/doris/load/routineload/KafkaRoutineLoadJob.java
index cb563e725db..579f860b46e 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/load/routineload/KafkaRoutineLoadJob.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/load/routineload/KafkaRoutineLoadJob.java
@@ -545,7 +545,12 @@ public class KafkaRoutineLoadJob extends RoutineLoadJob {
 
     private List<Integer> getAllKafkaPartitions() throws UserException {
         convertCustomProperties(false);
-        return KafkaUtil.getAllKafkaPartitions(brokerList, topic, 
convertedCustomProperties);
+        String computeGroupName = getComputeGroupName();
+        return KafkaUtil.getAllKafkaPartitions(brokerList, topic, 
convertedCustomProperties, computeGroupName);
+    }
+
+    private String getComputeGroupName() {
+        return Config.isCloudMode() ? getCloudCluster() : null;
     }
 
     public static KafkaRoutineLoadJob fromCreateInfo(CreateRoutineLoadInfo 
info, ConnectContext ctx)
@@ -639,13 +644,14 @@ public class KafkaRoutineLoadJob extends RoutineLoadJob {
         for (Integer kafkaPartition : newPartitions) {
             partitionOffsets.add(Pair.of(kafkaPartition, beginOffset));
         }
+        String computeGroupName = getComputeGroupName();
         try {
             if (isOffsetForTimes()) {
                 partitionOffsets = 
KafkaUtil.getOffsetsForTimes(this.brokerList,
-                        this.topic, convertedCustomProperties, 
partitionOffsets);
+                        this.topic, convertedCustomProperties, 
partitionOffsets, computeGroupName);
             } else {
                 partitionOffsets = KafkaUtil.getRealOffsets(this.brokerList,
-                        this.topic, convertedCustomProperties, 
partitionOffsets);
+                        this.topic, convertedCustomProperties, 
partitionOffsets, computeGroupName);
             }
         } catch (LoadException e) {
             LOG.warn(new LogBuilder(LogKey.ROUTINE_LOAD_JOB, id)
@@ -677,15 +683,18 @@ public class KafkaRoutineLoadJob extends RoutineLoadJob {
 
         List<Pair<Integer, Long>> kafkaPartitionOffsets = 
kafkaDataSourceProperties.getKafkaPartitionOffsets();
         boolean isForTimes = kafkaDataSourceProperties.isOffsetsForTimes();
+        String computeGroupName = getComputeGroupName();
         if (isForTimes) {
             // the offset is set by date time, we need to get the real offset 
by time
             kafkaPartitionOffsets = 
KafkaUtil.getOffsetsForTimes(kafkaDataSourceProperties.getBrokerList(),
                     kafkaDataSourceProperties.getTopic(),
-                    convertedCustomProperties, 
kafkaDataSourceProperties.getKafkaPartitionOffsets());
+                    convertedCustomProperties, 
kafkaDataSourceProperties.getKafkaPartitionOffsets(),
+                    computeGroupName);
         } else {
             kafkaPartitionOffsets = 
KafkaUtil.getRealOffsets(kafkaDataSourceProperties.getBrokerList(),
                     kafkaDataSourceProperties.getTopic(),
-                    convertedCustomProperties, 
kafkaDataSourceProperties.getKafkaPartitionOffsets());
+                    convertedCustomProperties, 
kafkaDataSourceProperties.getKafkaPartitionOffsets(),
+                    computeGroupName);
         }
 
         for (Pair<Integer, Long> partitionOffset : kafkaPartitionOffsets) {
@@ -783,11 +792,14 @@ public class KafkaRoutineLoadJob extends RoutineLoadJob {
         if (partitionOffsets.isEmpty()) {
             return;
         }
+        String computeGroupName = getComputeGroupName();
         List<Pair<Integer, Long>> newOffsets;
         if (dataSourceProperties.isOffsetsForTimes()) {
-            newOffsets = KafkaUtil.getOffsetsForTimes(brokerList, topic, 
convertedCustomProperties, partitionOffsets);
+            newOffsets = KafkaUtil.getOffsetsForTimes(
+                    brokerList, topic, convertedCustomProperties, 
partitionOffsets, computeGroupName);
         } else {
-            newOffsets = KafkaUtil.getRealOffsets(brokerList, topic, 
convertedCustomProperties, partitionOffsets);
+            newOffsets = KafkaUtil.getRealOffsets(
+                    brokerList, topic, convertedCustomProperties, 
partitionOffsets, computeGroupName);
         }
         dataSourceProperties.setKafkaPartitionOffsets(newOffsets);
     }
@@ -943,8 +955,10 @@ public class KafkaRoutineLoadJob extends RoutineLoadJob {
             } finally {
                 writeUnlock();
             }
+            String computeGroupName = getComputeGroupName();
             List<Pair<Integer, Long>> tmp = KafkaUtil.getLatestOffsets(id, 
taskId, brokerListSnapshot,
-                    topicSnapshot, customPropertiesSnapshot, 
Lists.newArrayList(partitionIdToOffset.keySet()));
+                    topicSnapshot, customPropertiesSnapshot, 
Lists.newArrayList(partitionIdToOffset.keySet()),
+                    computeGroupName);
             updateLatestOffsetsCache(tmp, taskId);
         } catch (Exception e) {
             // It needs to pause job when can not get partition meta.
@@ -1007,8 +1021,9 @@ public class KafkaRoutineLoadJob extends RoutineLoadJob {
             writeUnlock();
         }
         UUID taskId = UUID.randomUUID();
+        String computeGroupName = getComputeGroupName();
         List<Pair<Integer, Long>> latestOffsets = 
KafkaUtil.getLatestOffsets(id, taskId, brokerListSnapshot,
-                topicSnapshot, customPropertiesSnapshot, partitionIds);
+                topicSnapshot, customPropertiesSnapshot, partitionIds, 
computeGroupName);
         updateLatestOffsetsCache(latestOffsets, taskId);
     }
 
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/datasource/kafka/KafkaUtilTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/kafka/KafkaUtilTest.java
new file mode 100644
index 00000000000..1036ff93834
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/kafka/KafkaUtilTest.java
@@ -0,0 +1,150 @@
+// 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.doris.datasource.kafka;
+
+import org.apache.doris.catalog.Env;
+import org.apache.doris.cloud.system.CloudSystemInfoService;
+import org.apache.doris.common.Config;
+import org.apache.doris.common.LoadException;
+import org.apache.doris.load.routineload.RoutineLoadManager;
+import org.apache.doris.system.Backend;
+import org.apache.doris.system.SystemInfoService;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+public class KafkaUtilTest {
+    @Test
+    public void testGetInfoFailureMessageIncludesComputeGroup() {
+        Assert.assertEquals("failed to get info: no alive backends, compute 
group: routine-load-compute-group,",
+                KafkaUtil.getInfoFailureMessage("no alive backends", 
"routine-load-compute-group"));
+        Assert.assertEquals("failed to get info: no alive backends,",
+                KafkaUtil.getInfoFailureMessage("no alive backends", null));
+    }
+
+    @Test
+    public void testGetBackendIdsForMetaRequestUsesRoutineLoadComputeGroup() 
throws Exception {
+        String originalCloudUniqueId = Config.cloud_unique_id;
+        Backend routineLoadBackend = new Backend(10001L, "127.0.0.1", 9050);
+        Backend otherComputeGroupBackend = new Backend(10002L, "127.0.0.2", 
9050);
+        CloudSystemInfoService systemInfoService = 
Mockito.mock(CloudSystemInfoService.class);
+        
Mockito.when(systemInfoService.getBackendsByClusterName("routine-load-compute-group"))
+                .thenReturn(Collections.singletonList(routineLoadBackend));
+        Mockito.when(systemInfoService.getAllBackendIds(true))
+                .thenReturn(Arrays.asList(routineLoadBackend.getId(), 
otherComputeGroupBackend.getId()));
+
+        try (MockedStatic<Env> envStatic = Mockito.mockStatic(Env.class)) {
+            Config.cloud_unique_id = "test-cloud";
+            
envStatic.when(Env::getCurrentSystemInfo).thenReturn(systemInfoService);
+
+            List<Long> backendIds = 
KafkaUtil.getBackendIdsForMetaRequest("routine-load-compute-group");
+
+            
Assert.assertEquals(Collections.singletonList(routineLoadBackend.getId()), 
backendIds);
+            
Mockito.verify(systemInfoService).getBackendsByClusterName("routine-load-compute-group");
+            Mockito.verify(systemInfoService, 
Mockito.never()).getAllBackendIds(true);
+        } finally {
+            Config.cloud_unique_id = originalCloudUniqueId;
+        }
+    }
+
+    @Test
+    public void 
testGetAvailableBackendIdsForMetaRequestKeepsBlacklistFallbackInComputeGroup() {
+        long routineLoadBackendId = 10001L;
+        long otherComputeGroupBackendId = 10002L;
+        Backend routineLoadBackend = mockAvailableBackend();
+        Backend otherComputeGroupBackend = mockAvailableBackend();
+        SystemInfoService systemInfoService = 
Mockito.mock(SystemInfoService.class);
+        
Mockito.when(systemInfoService.getBackend(routineLoadBackendId)).thenReturn(routineLoadBackend);
+        
Mockito.when(systemInfoService.getBackend(otherComputeGroupBackendId)).thenReturn(otherComputeGroupBackend);
+
+        RoutineLoadManager routineLoadManager = 
Mockito.mock(RoutineLoadManager.class);
+        
Mockito.when(routineLoadManager.isInBlacklist(routineLoadBackendId)).thenReturn(true);
+        Map<Long, Long> blacklist = new HashMap<>();
+        blacklist.put(routineLoadBackendId, 1L);
+        blacklist.put(otherComputeGroupBackendId, 1L);
+        Mockito.when(routineLoadManager.getBlacklist()).thenReturn(blacklist);
+        Env env = Mockito.mock(Env.class);
+        
Mockito.when(env.getRoutineLoadManager()).thenReturn(routineLoadManager);
+
+        try (MockedStatic<Env> envStatic = Mockito.mockStatic(Env.class)) {
+            
envStatic.when(Env::getCurrentSystemInfo).thenReturn(systemInfoService);
+            envStatic.when(Env::getCurrentEnv).thenReturn(env);
+
+            List<Long> backendIds = 
KafkaUtil.getAvailableBackendIdsForMetaRequest(
+                    Collections.singletonList(routineLoadBackendId), new 
HashSet<>());
+
+            
Assert.assertEquals(Collections.singletonList(routineLoadBackendId), 
backendIds);
+            Mockito.verify(systemInfoService, 
Mockito.never()).getBackend(otherComputeGroupBackendId);
+        }
+    }
+
+    @Test
+    public void 
testGetBackendIdsForMetaRequestRejectsMissingCloudComputeGroup() {
+        String originalCloudUniqueId = Config.cloud_unique_id;
+        CloudSystemInfoService systemInfoService = 
Mockito.mock(CloudSystemInfoService.class);
+
+        try (MockedStatic<Env> envStatic = Mockito.mockStatic(Env.class)) {
+            Config.cloud_unique_id = "test-cloud";
+            
envStatic.when(Env::getCurrentSystemInfo).thenReturn(systemInfoService);
+
+            LoadException nullException = Assert.assertThrows(
+                    LoadException.class, () -> 
KafkaUtil.getBackendIdsForMetaRequest(null));
+            LoadException emptyException = Assert.assertThrows(
+                    LoadException.class, () -> 
KafkaUtil.getBackendIdsForMetaRequest(""));
+
+            Assert.assertEquals("compute group is empty when getting kafka 
meta", nullException.getDetailMessage());
+            Assert.assertEquals("compute group is empty when getting kafka 
meta", emptyException.getDetailMessage());
+            Mockito.verifyNoInteractions(systemInfoService);
+        } finally {
+            Config.cloud_unique_id = originalCloudUniqueId;
+        }
+    }
+
+    @Test
+    public void testGetBackendIdsForMetaRequestPreservesNonCloudSelection() 
throws Exception {
+        String originalCloudUniqueId = Config.cloud_unique_id;
+        SystemInfoService systemInfoService = 
Mockito.mock(SystemInfoService.class);
+        List<Long> allBackendIds = Arrays.asList(10001L, 10002L);
+        
Mockito.when(systemInfoService.getAllBackendIds(true)).thenReturn(allBackendIds);
+
+        try (MockedStatic<Env> envStatic = Mockito.mockStatic(Env.class)) {
+            Config.cloud_unique_id = "";
+            
envStatic.when(Env::getCurrentSystemInfo).thenReturn(systemInfoService);
+
+            Assert.assertEquals(allBackendIds, 
KafkaUtil.getBackendIdsForMetaRequest(null));
+            Mockito.verify(systemInfoService).getAllBackendIds(true);
+        } finally {
+            Config.cloud_unique_id = originalCloudUniqueId;
+        }
+    }
+
+    private Backend mockAvailableBackend() {
+        Backend backend = Mockito.mock(Backend.class);
+        Mockito.when(backend.isLoadAvailable()).thenReturn(true);
+        return backend;
+    }
+}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/load/routineload/KafkaRoutineLoadJobTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/load/routineload/KafkaRoutineLoadJobTest.java
index 2565f26a15b..19ebc50ffbb 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/load/routineload/KafkaRoutineLoadJobTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/load/routineload/KafkaRoutineLoadJobTest.java
@@ -206,30 +206,38 @@ public class KafkaRoutineLoadJobTest {
 
     @Test
     public void testUpdateLagRefreshesLatestOffsetCache() throws UserException 
{
-        KafkaRoutineLoadJob routineLoadJob = new KafkaRoutineLoadJob(1L, 
"kafka_routine_load_job", 1L,
-                1L, "127.0.0.1:9020", "topic1", UserIdentity.ADMIN);
-        Map<Integer, Long> partitionIdToOffset = Maps.newHashMap();
-        partitionIdToOffset.put(1, 10L);
-        partitionIdToOffset.put(2, 20L);
-        Deencapsulation.setField(routineLoadJob, "progress", new 
KafkaProgress(partitionIdToOffset));
-
-        new MockUp<KafkaUtil>() {
-            @Mock
-            public List<Pair<Integer, Long>> getLatestOffsets(long jobId, UUID 
taskId, String brokerList, String topic,
-                                                              Map<String, 
String> convertedCustomProperties,
-                                                              List<Integer> 
partitionIds) {
-                Assert.assertEquals(1L, jobId);
-                Assert.assertEquals("127.0.0.1:9020", brokerList);
-                Assert.assertEquals("topic1", topic);
-                Assert.assertTrue(partitionIds.contains(1));
-                Assert.assertTrue(partitionIds.contains(2));
-                return Lists.newArrayList(Pair.of(1, 15L), Pair.of(2, 30L));
-            }
-        };
-
-        routineLoadJob.updateLag();
-
-        Assert.assertEquals(15L, routineLoadJob.totalLag().longValue());
+        String originalCloudUniqueId = Config.cloud_unique_id;
+        try {
+            Config.cloud_unique_id = "test-cloud";
+            KafkaRoutineLoadJob routineLoadJob = new KafkaRoutineLoadJob(1L, 
"kafka_routine_load_job", 1L,
+                    1L, "127.0.0.1:9020", "topic1", UserIdentity.ADMIN);
+            routineLoadJob.setCloudCluster("routine-load-compute-group");
+            Map<Integer, Long> partitionIdToOffset = Maps.newHashMap();
+            partitionIdToOffset.put(1, 10L);
+            partitionIdToOffset.put(2, 20L);
+            Deencapsulation.setField(routineLoadJob, "progress", new 
KafkaProgress(partitionIdToOffset));
+
+            new MockUp<KafkaUtil>() {
+                @Mock
+                public List<Pair<Integer, Long>> getLatestOffsets(long jobId, 
UUID taskId, String brokerList,
+                        String topic, Map<String, String> 
convertedCustomProperties, List<Integer> partitionIds,
+                        String cloudCluster) {
+                    Assert.assertEquals(1L, jobId);
+                    Assert.assertEquals("127.0.0.1:9020", brokerList);
+                    Assert.assertEquals("topic1", topic);
+                    Assert.assertTrue(partitionIds.contains(1));
+                    Assert.assertTrue(partitionIds.contains(2));
+                    Assert.assertEquals("routine-load-compute-group", 
cloudCluster);
+                    return Lists.newArrayList(Pair.of(1, 15L), Pair.of(2, 
30L));
+                }
+            };
+
+            routineLoadJob.updateLag();
+
+            Assert.assertEquals(15L, routineLoadJob.totalLag().longValue());
+        } finally {
+            Config.cloud_unique_id = originalCloudUniqueId;
+        }
     }
 
     @Test
@@ -414,11 +422,12 @@ public class KafkaRoutineLoadJobTest {
             @Mock
             public List<Pair<Integer, Long>> getLatestOffsets(long jobId, UUID 
taskId, String brokerList, String topic,
                                                               Map<String, 
String> convertedCustomProperties,
-                                                              List<Integer> 
partitionIds) {
+                                                              List<Integer> 
partitionIds, String cloudCluster) {
                 Assert.assertEquals("SASL_PLAINTEXT", 
convertedCustomProperties.get("security.protocol"));
                 Assert.assertEquals("PLAIN", 
convertedCustomProperties.get("sasl.mechanism"));
                 Assert.assertEquals(1, partitionIds.size());
                 Assert.assertTrue(partitionIds.contains(1));
+                Assert.assertNull(cloudCluster);
                 return Lists.newArrayList(Pair.of(1, 15L));
             }
         };
@@ -516,7 +525,8 @@ public class KafkaRoutineLoadJobTest {
         new MockUp<KafkaUtil>() {
             @Mock
             public List<Integer> getAllKafkaPartitions(String brokerList, 
String topic,
-                    Map<String, String> convertedCustomProperties) throws 
UserException {
+                    Map<String, String> convertedCustomProperties, String 
cloudCluster) throws UserException {
+                Assert.assertNull(cloudCluster);
                 return Lists.newArrayList(1, 2, 3);
             }
         };
@@ -525,8 +535,10 @@ public class KafkaRoutineLoadJobTest {
             @Mock
             public List<Pair<Integer, Long>> getRealOffsets(String brokerList, 
String topic,
                                                              Map<String, 
String> convertedCustomProperties,
-                                                             
List<Pair<Integer, Long>> offsetFlags)
+                                                             
List<Pair<Integer, Long>> offsetFlags,
+                                                             String 
cloudCluster)
                                                              throws 
LoadException {
+                Assert.assertNull(cloudCluster);
                 List<Pair<Integer, Long>> pairList = new ArrayList<>();
                 pairList.add(Pair.of(1, 0L));
                 pairList.add(Pair.of(2, 0L));
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/load/routineload/RoutineLoadJobTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/load/routineload/RoutineLoadJobTest.java
index cc6962560f8..4b60b956d9e 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/load/routineload/RoutineLoadJobTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/load/routineload/RoutineLoadJobTest.java
@@ -293,7 +293,8 @@ public class RoutineLoadJobTest {
         new MockUp<KafkaUtil>() {
             @Mock
             public List<Integer> getAllKafkaPartitions(String brokerList, 
String topic,
-                    Map<String, String> convertedCustomProperties) throws 
UserException {
+                    Map<String, String> convertedCustomProperties, String 
cloudCluster) throws UserException {
+                Assert.assertNull(cloudCluster);
                 return Lists.newArrayList(1, 2, 3);
             }
         };
@@ -302,8 +303,10 @@ public class RoutineLoadJobTest {
             @Mock
             public List<Pair<Integer, Long>> getRealOffsets(String brokerList, 
String topic,
                                                              Map<String, 
String> convertedCustomProperties,
-                                                             
List<Pair<Integer, Long>> offsetFlags)
+                                                             
List<Pair<Integer, Long>> offsetFlags,
+                                                             String 
cloudCluster)
                                                              throws 
LoadException {
+                Assert.assertNull(cloudCluster);
                 List<Pair<Integer, Long>> pairList = new ArrayList<>();
                 pairList.add(Pair.of(1, 0L));
                 return pairList;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to