This is an automated email from the ASF dual-hosted git repository.
Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new 3d9678ffef perf(admin): batch discovery synchronization queries (#7268)
3d9678ffef is described below
commit 3d9678ffef656f0090c98fdce80d9ef001429d36
Author: Liming Deng <[email protected]>
AuthorDate: Tue Oct 20 14:30:31 2026 +0800
perf(admin): batch discovery synchronization queries (#7268)
* perf(admin): batch discovery synchronization queries
* fix(admin): tolerate and report invalid discovery batch bindings
* fix(admin): guard empty discovery relation batch queries
* fix(admin): preserve rollback when batch upstream sync fails
---
.../shenyu/admin/mapper/DiscoveryRelMapper.java | 8 ++
.../service/impl/DiscoveryUpstreamServiceImpl.java | 93 ++++++++-----
.../resources/mappers/discovery-rel-sqlmap.xml | 15 ++
.../admin/mapper/DiscoveryBatchQueryTest.java | 78 +++++++++++
.../service/DiscoveryUpstreamServiceTest.java | 153 +++++++++++++++++++--
5 files changed, 301 insertions(+), 46 deletions(-)
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryRelMapper.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryRelMapper.java
index 6b764382d2..0c4dd0b33d 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryRelMapper.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryRelMapper.java
@@ -44,6 +44,14 @@ public interface DiscoveryRelMapper {
*/
List<DiscoveryRelDO> selectAll();
+ /**
+ * Select rows for a bounded batch of discovery handlers.
+ *
+ * @param handlerIds handler ids
+ * @return matching rows
+ */
+ List<DiscoveryRelDO> selectByDiscoveryHandlerIds(@Param("handlerIds")
List<String> handlerIds);
+
/**
* Select related rows for one page in a single query.
*
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/DiscoveryUpstreamServiceImpl.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/DiscoveryUpstreamServiceImpl.java
index 515a6b7e63..0004cb43c0 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/DiscoveryUpstreamServiceImpl.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/DiscoveryUpstreamServiceImpl.java
@@ -54,6 +54,7 @@ import
org.springframework.transaction.support.TransactionSynchronization;
import
org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.StringUtils;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
@@ -62,12 +63,16 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
+import java.util.function.Function;
@Service
public class DiscoveryUpstreamServiceImpl implements DiscoveryUpstreamService {
private static final Logger LOG =
LoggerFactory.getLogger(DiscoveryUpstreamServiceImpl.class);
+ // Keep IN lists below Oracle's 1000-expression limit and bound query
payloads on all databases.
+ private static final int BATCH_SIZE = 500;
+
private final DiscoveryUpstreamMapper discoveryUpstreamMapper;
private final DiscoveryHandlerMapper discoveryHandlerMapper;
@@ -145,6 +150,11 @@ public class DiscoveryUpstreamServiceImpl implements
DiscoveryUpstreamService {
discoveryUpstreamDO.setDiscoveryHandlerId(discoveryHandlerId);
discoveryUpstreamMapper.insert(discoveryUpstreamDO);
}
+ fetchAfterCommit(discoveryHandlerId);
+ return 0;
+ }
+
+ private void fetchAfterCommit(final String discoveryHandlerId) {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(new
TransactionSynchronization() {
@Override
@@ -155,7 +165,6 @@ public class DiscoveryUpstreamServiceImpl implements
DiscoveryUpstreamService {
} else {
this.fetchAll(discoveryHandlerId);
}
- return 0;
}
@Override
@@ -197,41 +206,59 @@ public class DiscoveryUpstreamServiceImpl implements
DiscoveryUpstreamService {
return
buildSyncData(discoveryHandlerMapper.selectAllByNamespaceId(namespaceId));
}
- private List<DiscoverySyncData> buildSyncData(final
List<DiscoveryHandlerDO> discoveryHandlerDOS) {
- return discoveryHandlerDOS.stream().map(d -> {
- DiscoveryRelDO discoveryRelDO =
discoveryRelMapper.selectByDiscoveryHandlerId(d.getId());
- if (Objects.isNull(discoveryRelDO)) {
- LOG.warn("Skipping discovery handler {} without a relation",
d.getId());
- return null;
- }
- DiscoverySyncData discoverySyncData = new DiscoverySyncData();
- discoverySyncData.setPluginName(discoveryRelDO.getPluginName());
- if (StringUtils.hasLength(discoveryRelDO.getSelectorId())) {
- String selectorId = discoveryRelDO.getSelectorId();
- discoverySyncData.setSelectorId(selectorId);
- SelectorDO selectorDO = selectorMapper.selectById(selectorId);
- if (Objects.isNull(selectorDO)) {
- LOG.warn("Skipping discovery handler {} with missing
selector {}", d.getId(), selectorId);
- return null;
+ private List<DiscoverySyncData> buildSyncData(final
List<DiscoveryHandlerDO> handlers) {
+ List<DiscoverySyncData> result = new ArrayList<>();
+ for (List<DiscoveryHandlerDO> batch : Lists.partition(handlers,
BATCH_SIZE)) {
+ List<String> handlerIds =
batch.stream().map(DiscoveryHandlerDO::getId).collect(Collectors.toList());
+ List<DiscoveryRelDO> relations =
discoveryRelMapper.selectByDiscoveryHandlerIds(handlerIds);
+ Set<String> selectorIds =
relations.stream().map(DiscoveryRelDO::getSelectorId).filter(StringUtils::hasLength).collect(Collectors.toSet());
+ List<String> proxyIds = relations.stream().filter(rel ->
!StringUtils.hasLength(rel.getSelectorId()))
+
.map(DiscoveryRelDO::getProxySelectorId).filter(StringUtils::hasLength).distinct().collect(Collectors.toList());
+ Map<String, SelectorDO> selectors = selectorIds.isEmpty() ?
Collections.emptyMap()
+ :
selectorMapper.selectByIdSet(selectorIds).stream().collect(Collectors.toMap(SelectorDO::getId,
Function.identity()));
+ Map<String, ProxySelectorDO> proxies = proxyIds.isEmpty() ?
Collections.emptyMap()
+ :
proxySelectorMapper.selectByIds(proxyIds).stream().collect(Collectors.toMap(ProxySelectorDO::getId,
Function.identity()));
+ Map<String, List<DiscoveryUpstreamData>> upstreams =
discoveryUpstreamMapper.selectByDiscoveryHandlerIds(handlerIds).stream()
+
.collect(Collectors.groupingBy(DiscoveryUpstreamDO::getDiscoveryHandlerId,
+
Collectors.mapping(DiscoveryTransfer.INSTANCE::mapToData,
Collectors.toList())));
+ Map<String, DiscoveryRelDO> relationByHandler = relations.stream()
+
.collect(Collectors.toMap(DiscoveryRelDO::getDiscoveryHandlerId,
Function.identity(), (existing, duplicate) -> {
+ LOG.warn("Duplicate discovery relations for handler
{}, retaining relation {} and ignoring {}",
+ existing.getDiscoveryHandlerId(),
existing.getId(), duplicate.getId());
+ return existing;
+ }));
+ for (DiscoveryHandlerDO handler : batch) {
+ DiscoveryRelDO relation =
relationByHandler.get(handler.getId());
+ if (Objects.isNull(relation)) {
+ LOG.warn("Skipping discovery handler {}: relation is
missing", handler.getId());
+ continue;
}
-
discoverySyncData.setSelectorName(selectorDO.getSelectorName());
- discoverySyncData.setNamespaceId(selectorDO.getNamespaceId());
- } else {
- String proxySelectorId = discoveryRelDO.getProxySelectorId();
- discoverySyncData.setSelectorId(proxySelectorId);
- ProxySelectorDO proxySelectorDO =
proxySelectorMapper.selectById(proxySelectorId);
- if (Objects.isNull(proxySelectorDO)) {
- LOG.warn("Skipping discovery handler {} with missing proxy
selector {}", d.getId(), proxySelectorId);
- return null;
+ DiscoverySyncData data = new DiscoverySyncData();
+ data.setPluginName(relation.getPluginName());
+ if (StringUtils.hasLength(relation.getSelectorId())) {
+ SelectorDO selector =
selectors.get(relation.getSelectorId());
+ if (Objects.isNull(selector)) {
+ LOG.warn("Skipping discovery handler {}: selector {}
is missing", handler.getId(), relation.getSelectorId());
+ continue;
+ }
+ data.setSelectorId(selector.getId());
+ data.setSelectorName(selector.getSelectorName());
+ data.setNamespaceId(selector.getNamespaceId());
+ } else {
+ ProxySelectorDO proxy =
proxies.get(relation.getProxySelectorId());
+ if (Objects.isNull(proxy)) {
+ LOG.warn("Skipping discovery handler {}: proxy
selector {} is missing", handler.getId(), relation.getProxySelectorId());
+ continue;
+ }
+ data.setSelectorId(proxy.getId());
+ data.setSelectorName(proxy.getName());
+ data.setNamespaceId(proxy.getNamespaceId());
}
- discoverySyncData.setSelectorName(proxySelectorDO.getName());
-
discoverySyncData.setNamespaceId(proxySelectorDO.getNamespaceId());
+
data.setUpstreamDataList(upstreams.getOrDefault(handler.getId(),
Collections.emptyList()));
+ result.add(data);
}
- List<DiscoveryUpstreamData> discoveryUpstreamDataList =
discoveryUpstreamMapper.selectByDiscoveryHandlerId(d.getId()).stream()
-
.map(DiscoveryTransfer.INSTANCE::mapToData).collect(Collectors.toList());
- discoverySyncData.setUpstreamDataList(discoveryUpstreamDataList);
- return discoverySyncData;
- }).filter(Objects::nonNull).collect(Collectors.toList());
+ }
+ return result;
}
@Override
diff --git a/shenyu-admin/src/main/resources/mappers/discovery-rel-sqlmap.xml
b/shenyu-admin/src/main/resources/mappers/discovery-rel-sqlmap.xml
index 34534ec01e..25b02fd9ae 100644
--- a/shenyu-admin/src/main/resources/mappers/discovery-rel-sqlmap.xml
+++ b/shenyu-admin/src/main/resources/mappers/discovery-rel-sqlmap.xml
@@ -45,6 +45,21 @@
WHERE id = #{id, jdbcType=VARCHAR}
</select>
+ <select id="selectByDiscoveryHandlerIds" resultMap="BaseResultMap">
+ SELECT <include refid="Base_Column_List"/>
+ FROM discovery_rel
+ WHERE
+ <choose>
+ <when test="handlerIds != null and handlerIds.size() > 0">
+ discovery_handler_id IN
+ <foreach collection="handlerIds" item="handlerId" open="("
separator="," close=")">
+ #{handlerId}
+ </foreach>
+ </when>
+ <otherwise>1 = 0</otherwise>
+ </choose>
+ </select>
+
<select id="selectAll" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
diff --git
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryBatchQueryTest.java
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryBatchQueryTest.java
new file mode 100644
index 0000000000..6e5e130d27
--- /dev/null
+++
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryBatchQueryTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.shenyu.admin.mapper;
+
+import org.apache.ibatis.builder.xml.XMLMapperBuilder;
+import org.apache.ibatis.mapping.Environment;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactoryBuilder;
+import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
+import org.junit.jupiter.api.Test;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.UUID;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class DiscoveryBatchQueryTest {
+
+ @Test
+ void readsOnlyRowsForRequestedHandlers() throws Exception {
+ DriverManagerDataSource dataSource = new DriverManagerDataSource(
+ "jdbc:h2:mem:discovery-batch-" + UUID.randomUUID() +
";DB_CLOSE_DELAY=-1;MODE=MySQL", "sa", "");
+ JdbcTemplate jdbc = new JdbcTemplate(dataSource);
+ try {
+ new ResourceDatabasePopulator(new
ClassPathResource("sql-script/h2/schema.sql")).execute(dataSource);
+ for (String id : List.of("a", "b", "c")) {
+ jdbc.update("INSERT INTO discovery_rel (id, plugin_name,
discovery_handler_id, selector_id) VALUES (?, 'divide', ?, ?)", id, id, "s-" +
id);
+ jdbc.update("INSERT INTO discovery_upstream (id,
discovery_handler_id, namespace_id, upstream_url, upstream_status, weight) "
+ + "VALUES (?, ?, 'namespace', 'localhost:8080', 0,
50)", id, id);
+ }
+ Configuration configuration = new Configuration(new
Environment("test", new JdbcTransactionFactory(), dataSource));
+ for (String mapper : List.of("discovery-rel",
"discovery-upstream")) {
+ try (InputStream input = new ClassPathResource("mappers/" +
mapper + "-sqlmap.xml").getInputStream()) {
+ new XMLMapperBuilder(input, configuration, mapper,
configuration.getSqlFragments()).parse();
+ }
+ }
+ try (SqlSession session = new
SqlSessionFactoryBuilder().build(configuration).openSession()) {
+ DiscoveryRelMapper relations =
session.getMapper(DiscoveryRelMapper.class);
+ DiscoveryUpstreamMapper upstreams =
session.getMapper(DiscoveryUpstreamMapper.class);
+ assertEquals(2,
relations.selectByDiscoveryHandlerIds(List.of("a", "b")).size());
+ assertEquals(2,
upstreams.selectByDiscoveryHandlerIds(List.of("a", "b")).size());
+ assertEquals("s-c",
relations.selectByDiscoveryHandlerIds(List.of("c")).get(0).getSelectorId());
+ assertEquals("c",
upstreams.selectByDiscoveryHandlerIds(List.of("c")).get(0).getDiscoveryHandlerId());
+
assertTrue(relations.selectByDiscoveryHandlerIds(List.of("missing")).isEmpty());
+
assertTrue(upstreams.selectByDiscoveryHandlerIds(List.of("missing")).isEmpty());
+
assertTrue(upstreams.selectByDiscoveryHandlerIds(List.of()).isEmpty());
+
assertTrue(upstreams.selectByDiscoveryHandlerIds(null).isEmpty());
+
assertTrue(relations.selectByDiscoveryHandlerIds(List.of()).isEmpty());
+
assertTrue(relations.selectByDiscoveryHandlerIds(null).isEmpty());
+ }
+ } finally {
+ jdbc.execute("SHUTDOWN");
+ }
+ }
+}
diff --git
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/DiscoveryUpstreamServiceTest.java
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/DiscoveryUpstreamServiceTest.java
index 7f4f0e66cd..0cfd83239b 100644
---
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/DiscoveryUpstreamServiceTest.java
+++
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/DiscoveryUpstreamServiceTest.java
@@ -58,7 +58,10 @@ import org.mockito.junit.jupiter.MockitoExtension;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Collections;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
import java.util.Locale;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -69,9 +72,10 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.when;
import org.springframework.test.util.ReflectionTestUtils;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verifyNoInteractions;
-import static org.mockito.Mockito.never;
/**
* Test cases for DiscoveryUpstreamService.
@@ -207,12 +211,135 @@ public final class DiscoveryUpstreamServiceTest {
List<DiscoveryHandlerDO> list =
Collections.singletonList(buildDiscoveryHandlerDO());
when(discoveryHandlerMapper.selectAll()).thenReturn(list);
-
when(discoveryRelMapper.selectByDiscoveryHandlerId(any())).thenReturn(buildDiscoveryRelDO());
-
when(proxySelectorMapper.selectById(any())).thenReturn(buildProxySelectorDO());
+ DiscoveryRelDO relation = buildDiscoveryRelDO();
+ relation.setDiscoveryHandlerId("123");
+ relation.setProxySelectorId("selector_1");
+
when(discoveryRelMapper.selectByDiscoveryHandlerIds(any())).thenReturn(Collections.singletonList(relation));
+
when(proxySelectorMapper.selectByIds(any())).thenReturn(Collections.singletonList(buildProxySelectorDO()));
List<DiscoverySyncData> dataList = discoveryUpstreamService.listAll();
assertEquals(dataList.size(), list.size());
}
+ @ParameterizedTest
+ @ValueSource(ints = {20, 501})
+ void batchesQueriesAndPreservesHandlerOrder(final int count) {
+ List<DiscoveryHandlerDO> handlers = new ArrayList<>();
+ for (int i = 0; i < count; i++) {
+ DiscoveryHandlerDO handler = buildDiscoveryHandlerDO();
+ handler.setId(String.valueOf(i));
+ handlers.add(handler);
+ }
+ when(discoveryHandlerMapper.selectAll()).thenReturn(handlers);
+
when(discoveryRelMapper.selectByDiscoveryHandlerIds(any())).thenAnswer(invocation
-> {
+ List<String> ids = invocation.getArgument(0);
+ Assertions.assertTrue(ids.size() <= 500);
+ return ids.stream().map(id -> {
+ DiscoveryRelDO relation = buildDiscoveryRelDO();
+ relation.setDiscoveryHandlerId(id);
+ if (Integer.parseInt(id) % 2 == 0) {
+ relation.setSelectorId(id);
+ } else {
+ relation.setProxySelectorId(id);
+ }
+ return relation;
+ }).collect(Collectors.toList());
+ });
+ when(selectorMapper.selectByIdSet(any())).thenAnswer(invocation -> {
+ java.util.Set<String> ids = invocation.getArgument(0);
+ return ids.stream().map(id -> {
+ SelectorDO selector = buildSelectorDO();
+ selector.setId(id);
+ return selector;
+ }).collect(Collectors.toList());
+ });
+ when(proxySelectorMapper.selectByIds(any())).thenAnswer(invocation -> {
+ List<String> ids = invocation.getArgument(0);
+ return ids.stream().map(id -> {
+ ProxySelectorDO proxy = buildProxySelectorDO();
+ proxy.setId(id);
+ return proxy;
+ }).collect(Collectors.toList());
+ });
+
when(discoveryUpstreamMapper.selectByDiscoveryHandlerIds(any())).thenAnswer(invocation
-> {
+ List<String> ids = invocation.getArgument(0);
+ return ids.stream().map(id -> buildDiscoveryUpstreamDO("u-" + id,
id, "localhost:8080")).collect(Collectors.toList());
+ });
+ List<DiscoverySyncData> data = discoveryUpstreamService.listAll();
+ assertEquals(count, data.size());
+ for (int i = 0; i < count; i++) {
+ assertEquals(String.valueOf(i), data.get(i).getSelectorId());
+ assertEquals(1, data.get(i).getUpstreamDataList().size());
+ }
+ int batches = (count + 499) / 500;
+ verify(discoveryHandlerMapper).selectAll();
+ verify(discoveryRelMapper,
times(batches)).selectByDiscoveryHandlerIds(any());
+ verify(discoveryUpstreamMapper,
times(batches)).selectByDiscoveryHandlerIds(any());
+ verify(selectorMapper, times(batches)).selectByIdSet(any());
+ verify(proxySelectorMapper, times(count / 500 + (count % 500 > 1 ? 1 :
0))).selectByIds(any());
+ verify(discoveryRelMapper, never()).selectByDiscoveryHandlerId(any());
+ verify(discoveryUpstreamMapper,
never()).selectByDiscoveryHandlerId(any());
+ verify(selectorMapper, never()).selectById(any());
+ verify(proxySelectorMapper, never()).selectById(any());
+ }
+
+ @Test
+ public void duplicateAndMissingBindingsDoNotAbortOtherHandlers() {
+ List<DiscoveryHandlerDO> handlers = new ArrayList<>();
+ for (String id : List.of("valid", "missing-relation",
"missing-selector", "missing-proxy")) {
+ DiscoveryHandlerDO handler = buildDiscoveryHandlerDO();
+ handler.setId(id);
+ handlers.add(handler);
+ }
+ DiscoveryRelDO valid = buildDiscoveryRelDO();
+ valid.setDiscoveryHandlerId("valid");
+ valid.setSelectorId("selector_1");
+ DiscoveryRelDO duplicate = buildDiscoveryRelDO();
+ duplicate.setDiscoveryHandlerId("valid");
+ duplicate.setSelectorId("missing");
+ DiscoveryRelDO missingSelector = buildDiscoveryRelDO();
+ missingSelector.setDiscoveryHandlerId("missing-selector");
+ missingSelector.setSelectorId("missing");
+ DiscoveryRelDO missingProxy = buildDiscoveryRelDO();
+ missingProxy.setDiscoveryHandlerId("missing-proxy");
+ missingProxy.setProxySelectorId("missing");
+ when(discoveryHandlerMapper.selectAll()).thenReturn(handlers);
+
when(discoveryRelMapper.selectByDiscoveryHandlerIds(any())).thenReturn(List.of(valid,
duplicate, missingSelector, missingProxy));
+
when(selectorMapper.selectByIdSet(any())).thenReturn(List.of(buildSelectorDO()));
+
when(proxySelectorMapper.selectByIds(any())).thenReturn(Collections.emptyList());
+
when(discoveryUpstreamMapper.selectByDiscoveryHandlerIds(any())).thenReturn(Collections.emptyList());
+
+ List<DiscoverySyncData> data = discoveryUpstreamService.listAll();
+
+ assertEquals(1, data.size());
+ assertEquals("selector_1", data.get(0).getSelectorId());
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = {true, false})
+ void batchesNamespaceSyncAndRetainsNamespace(final boolean proxy) {
+ final DiscoveryRelDO relation = buildDiscoveryRelDO();
+ relation.setDiscoveryHandlerId("123");
+
when(discoveryHandlerMapper.selectAllByNamespaceId("tenant")).thenReturn(List.of(buildDiscoveryHandlerDO()));
+ if (proxy) {
+ relation.setSelectorId("");
+ relation.setProxySelectorId("selector_1");
+ ProxySelectorDO selector = buildProxySelectorDO();
+ selector.setNamespaceId("tenant");
+
when(proxySelectorMapper.selectByIds(List.of("selector_1"))).thenReturn(List.of(selector));
+ } else {
+ relation.setSelectorId("selector_1");
+ SelectorDO selector = buildSelectorDO();
+ selector.setNamespaceId("tenant");
+
when(selectorMapper.selectByIdSet(Set.of("selector_1"))).thenReturn(List.of(selector));
+ }
+
when(discoveryRelMapper.selectByDiscoveryHandlerIds(List.of("123"))).thenReturn(List.of(relation));
+ List<DiscoverySyncData> data =
discoveryUpstreamService.listAllByNamespaceId("tenant");
+ assertEquals(1, data.size());
+ assertEquals("tenant", data.get(0).getNamespaceId());
+ verify(discoveryHandlerMapper, never()).selectAll();
+ verify(discoveryRelMapper, never()).selectByDiscoveryHandlerId(any());
+ }
+
@Test
public void testListAllSkipsOrphansAndKeepsValidBindings() {
DiscoveryHandlerDO noRelation = buildDiscoveryHandlerDO();
@@ -226,23 +353,23 @@ public final class DiscoveryUpstreamServiceTest {
DiscoveryHandlerDO validProxy = buildDiscoveryHandlerDO();
validProxy.setId("valid-proxy");
when(discoveryHandlerMapper.selectAll()).thenReturn(List.of(noRelation,
missingSelector, validSelector, missingProxy, validProxy));
-
when(discoveryRelMapper.selectByDiscoveryHandlerId("no-relation")).thenReturn(null);
DiscoveryRelDO staleSelectorRel = buildDiscoveryRelDO();
staleSelectorRel.setSelectorId("deleted-selector");
-
when(discoveryRelMapper.selectByDiscoveryHandlerId("missing-selector")).thenReturn(staleSelectorRel);
+ staleSelectorRel.setDiscoveryHandlerId("missing-selector");
DiscoveryRelDO staleProxyRel = buildDiscoveryRelDO();
staleProxyRel.setProxySelectorId("deleted-proxy");
-
when(discoveryRelMapper.selectByDiscoveryHandlerId("missing-proxy")).thenReturn(staleProxyRel);
+ staleProxyRel.setDiscoveryHandlerId("missing-proxy");
DiscoveryRelDO selectorRel = buildDiscoveryRelDO();
selectorRel.setSelectorId("selector_1");
-
when(discoveryRelMapper.selectByDiscoveryHandlerId("valid-selector")).thenReturn(selectorRel);
-
when(selectorMapper.selectById("selector_1")).thenReturn(buildSelectorDO());
- when(selectorMapper.selectById("deleted-selector")).thenReturn(null);
+ selectorRel.setDiscoveryHandlerId("valid-selector");
+ when(selectorMapper.selectByIdSet(Set.of("selector_1",
"deleted-selector"))).thenReturn(List.of(buildSelectorDO()));
DiscoveryRelDO proxyRel = buildDiscoveryRelDO();
proxyRel.setProxySelectorId("proxy_1");
-
when(discoveryRelMapper.selectByDiscoveryHandlerId("valid-proxy")).thenReturn(proxyRel);
-
when(proxySelectorMapper.selectById("proxy_1")).thenReturn(buildProxySelectorDO());
- when(proxySelectorMapper.selectById("deleted-proxy")).thenReturn(null);
+ proxyRel.setDiscoveryHandlerId("valid-proxy");
+
when(discoveryRelMapper.selectByDiscoveryHandlerIds(any())).thenReturn(List.of(staleSelectorRel,
staleProxyRel, selectorRel, proxyRel));
+ ProxySelectorDO proxy = buildProxySelectorDO();
+ proxy.setId("proxy_1");
+ when(proxySelectorMapper.selectByIds(List.of("deleted-proxy",
"proxy_1"))).thenReturn(List.of(proxy));
List<DiscoverySyncData> result = discoveryUpstreamService.listAll();
assertEquals(2, result.size());
assertEquals("selector_1", result.get(0).getSelectorId());
@@ -381,7 +508,7 @@ public final class DiscoveryUpstreamServiceTest {
}
@Test
- public void testRolledBackBatchDoesNotPublish() {
+ public void testRolledBackUpdateBatchDoesNotPublish() {
TransactionSynchronizationManager.initSynchronization();
try {
discoveryUpstreamService.updateBatch("123",
Collections.emptyList());