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 447206b995 perf(admin): coalesce selector import events (#7181)
447206b995 is described below
commit 447206b9952631380f9c843635988cb1eac5776e
Author: Liming Deng <[email protected]>
AuthorDate: Sat Oct 17 20:48:43 2026 +0800
perf(admin): coalesce selector import events (#7181)
---
.../admin/service/impl/SelectorServiceImpl.java | 48 ++++++++++++++++++----
.../shenyu/admin/service/SelectorServiceTest.java | 44 ++++++++++++++++++--
2 files changed, 80 insertions(+), 12 deletions(-)
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/SelectorServiceImpl.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/SelectorServiceImpl.java
index 5c08df0284..84718f352f 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/SelectorServiceImpl.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/SelectorServiceImpl.java
@@ -94,6 +94,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.LinkedHashMap;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@@ -515,6 +516,7 @@ public class SelectorServiceImpl implements SelectorService
{
}
StringBuilder errorMsgBuilder = new StringBuilder();
int successCount = 0;
+ List<SelectorData> importedSelectors = new ArrayList<>();
Map<String, List<SelectorDO>> pluginSelectorMap =
selectorMapper.selectAll().stream()
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(SelectorDO::getPluginId));
@@ -544,12 +546,14 @@ public class SelectorServiceImpl implements
SelectorService {
.append(selectorName)
.append(",");
} else {
- create(selectorDTO);
- successCount++;
+ if (createForImport(selectorDTO, importedSelectors) >
0) {
+ successCount++;
+ }
}
}
}
}
+ publishImportEvent(importedSelectors);
if (StringUtils.isNotEmpty(errorMsgBuilder)) {
errorMsgBuilder.setLength(errorMsgBuilder.length() - 1);
return ConfigImportResult
@@ -567,6 +571,7 @@ public class SelectorServiceImpl implements SelectorService
{
Map<String, String> selectorIdMapping = context.getSelectorIdMapping();
StringBuilder errorMsgBuilder = new StringBuilder();
int successCount = 0;
+ List<SelectorData> importedSelectors = new ArrayList<>();
Map<String, Map<String, String>> pluginSelectorMap =
selectorMapper.selectAllByNamespaceId(namespace).stream()
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(SelectorDO::getPluginId,
@@ -604,7 +609,7 @@ public class SelectorServiceImpl implements SelectorService
{
c.setSelectorId(selectorId);
c.setId(null);
});
- if (create(selectorDTO) > 0) {
+ if (createForImport(selectorDTO, importedSelectors) >
0) {
existSelectorSet.put(selectorName, selectorId);
selectorIdMapping.put(oldSelectorId, selectorId);
successCount++;
@@ -613,6 +618,7 @@ public class SelectorServiceImpl implements SelectorService
{
}
}
}
+ publishImportEvent(importedSelectors);
if (StringUtils.isNotEmpty(errorMsgBuilder)) {
errorMsgBuilder.setLength(errorMsgBuilder.length() - 1);
return ConfigImportResult
@@ -683,14 +689,40 @@ public class SelectorServiceImpl implements
SelectorService {
}
private void publishEvent(final SelectorDO selectorDO, final
List<SelectorConditionDTO> selectorConditions, final List<SelectorConditionDO>
beforeSelectorCondition) {
+ SelectorData selectorData = buildSelectorData(selectorDO,
selectorConditions, beforeSelectorCondition);
+ eventPublisher.publishEvent(new
DataChangedEvent(ConfigGroupEnum.SELECTOR, DataEventTypeEnum.UPDATE,
+ Collections.singletonList(selectorData)));
+ }
+
+ private int createForImport(final SelectorDTO selectorDTO, final
List<SelectorData> importedSelectors) {
+ SelectorDO selectorDO = SelectorDO.buildSelectorDO(selectorDTO);
+ final int selectorCount = selectorMapper.insertSelective(selectorDO);
+ selectorDTO.setId(selectorDO.getId());
+ createCondition(selectorDO.getId(),
selectorDTO.getSelectorConditions());
+ if (selectorCount > 0) {
+ importedSelectors.add(buildSelectorData(selectorDO,
selectorDTO.getSelectorConditions(), Collections.emptyList()));
+ selectorEventPublisher.onCreated(selectorDO);
+ }
+ return selectorCount;
+ }
+
+ private void publishImportEvent(final List<SelectorData>
importedSelectors) {
+ Map<String, List<SelectorData>> selectorsByNamespace = new
LinkedHashMap<>();
+ for (SelectorData selector : importedSelectors) {
+ String namespaceId =
StringUtils.defaultIfEmpty(selector.getNamespaceId(), SYS_DEFAULT_NAMESPACE_ID);
+ selector.setNamespaceId(namespaceId);
+ selectorsByNamespace.computeIfAbsent(namespaceId, key -> new
ArrayList<>()).add(selector);
+ }
+ selectorsByNamespace.values().forEach(selectors ->
+ eventPublisher.publishEvent(new
DataChangedEvent(ConfigGroupEnum.SELECTOR, DataEventTypeEnum.UPDATE,
selectors)));
+ }
+
+ private SelectorData buildSelectorData(final SelectorDO selectorDO, final
List<SelectorConditionDTO> selectorConditions,
+ final List<SelectorConditionDO>
beforeSelectorCondition) {
PluginDO pluginDO = pluginMapper.selectById(selectorDO.getPluginId());
List<ConditionData> conditionDataList =
ListUtil.map(selectorConditions, ConditionTransfer.INSTANCE::mapToSelectorDTO);
List<ConditionData> beforeConditionDataList =
ListUtil.map(beforeSelectorCondition,
ConditionTransfer.INSTANCE::mapToSelectorDO);
- // build selector data.
- SelectorData selectorData = SelectorDO.transFrom(selectorDO,
pluginDO.getName(), conditionDataList, beforeConditionDataList);
- // publish change event.
- eventPublisher.publishEvent(new
DataChangedEvent(ConfigGroupEnum.SELECTOR, DataEventTypeEnum.UPDATE,
- Collections.singletonList(selectorData)));
+ return SelectorDO.transFrom(selectorDO, pluginDO.getName(),
conditionDataList, beforeConditionDataList);
}
private SelectorData buildSelectorData(final SelectorDO selectorDO) {
diff --git
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/SelectorServiceTest.java
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/SelectorServiceTest.java
index 65cf361621..7aa746687b 100644
---
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/SelectorServiceTest.java
+++
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/SelectorServiceTest.java
@@ -20,6 +20,7 @@ package org.apache.shenyu.admin.service;
import org.apache.commons.lang3.StringUtils;
import org.apache.shenyu.admin.discovery.DiscoveryProcessor;
import org.apache.shenyu.admin.discovery.DiscoveryProcessorHolder;
+import org.apache.shenyu.admin.listener.DataChangedEvent;
import org.apache.shenyu.admin.exception.ShenyuAdminException;
import org.apache.shenyu.admin.mapper.DataPermissionMapper;
import org.apache.shenyu.admin.mapper.DiscoveryHandlerMapper;
@@ -51,11 +52,13 @@ import
org.apache.shenyu.admin.service.impl.SelectorServiceImpl;
import org.apache.shenyu.admin.service.publish.SelectorEventPublisher;
import org.apache.shenyu.admin.utils.JwtUtils;
import org.apache.shenyu.common.dto.SelectorData;
+import org.apache.shenyu.common.enums.ConfigGroupEnum;
import org.apache.shenyu.common.enums.SelectorTypeEnum;
import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
@@ -91,8 +94,9 @@ import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
-import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
@@ -347,7 +351,7 @@ public final class SelectorServiceTest {
final List<SelectorDO> selectorDOs = buildSelectorDOList();
given(this.selectorMapper.selectAll()).willReturn(selectorDOs);
- final List<SelectorDTO> selectorDTOs = buildSelectorDTOList();
+ final List<SelectorDTO> selectorDTOs =
Arrays.asList(buildSelectorDTO("456"), buildSelectorDTO("457"));
given(this.selectorMapper.insertSelective(any())).willReturn(1);
given(this.pluginMapper.selectById(any())).willReturn(buildPluginDO());
@@ -356,10 +360,42 @@ public final class SelectorServiceTest {
assertNotNull(configImportResult);
assertEquals(configImportResult.getSuccessCount(),
selectorDTOs.size());
+ ArgumentCaptor<DataChangedEvent> eventCaptor =
ArgumentCaptor.forClass(DataChangedEvent.class);
+ verify(eventPublisher, times(1)).publishEvent(eventCaptor.capture());
+ assertEquals(selectorDTOs.size(),
eventCaptor.getValue().getSource().size());
}
- private List<SelectorDTO> buildSelectorDTOList() {
- return Collections.singletonList(buildSelectorDTO("456"));
+ @Test
+ public void testGlobalImportPublishesOneEventPerNamespace() {
+ SelectorDTO first = buildSelectorDTO("first");
+ first.setNamespaceId("namespace-a");
+ SelectorDTO second = buildSelectorDTO("second");
+ second.setNamespaceId("namespace-b");
+ SelectorDTO third = buildSelectorDTO("third");
+ third.setNamespaceId("namespace-a");
+ SelectorDTO defaultSelector = buildSelectorDTO("default");
+ defaultSelector.setNamespaceId(null);
+ SelectorDTO emptyNamespace = buildSelectorDTO("empty");
+ emptyNamespace.setNamespaceId("");
+ given(selectorMapper.selectAll()).willReturn(Collections.emptyList());
+ given(selectorMapper.insertSelective(any())).willReturn(1);
+ given(pluginMapper.selectById(any())).willReturn(buildPluginDO());
+
+ ConfigImportResult result =
selectorService.importData(Arrays.asList(first, second, third, defaultSelector,
emptyNamespace));
+
+ assertEquals(5, result.getSuccessCount());
+ verify(selectorEventPublisher,
times(5)).onCreated(any(SelectorDO.class));
+ ArgumentCaptor<DataChangedEvent> events =
ArgumentCaptor.forClass(DataChangedEvent.class);
+ verify(eventPublisher, times(3)).publishEvent(events.capture());
+ List<DataChangedEvent> published = events.getAllValues();
+ assertEquals(Arrays.asList(2, 1, 2), published.stream().map(event ->
event.getSource().size()).toList());
+ List<String> namespaces = Arrays.asList("namespace-a", "namespace-b",
SYS_DEFAULT_NAMESPACE_ID);
+ for (int index = 0; index < published.size(); index++) {
+ assertEquals(ConfigGroupEnum.SELECTOR,
published.get(index).getGroupKey());
+ for (Object data : published.get(index).getSource()) {
+ assertEquals(namespaces.get(index), ((SelectorData)
data).getNamespaceId());
+ }
+ }
}
private void testUpdate() {