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 eb7428279f fix(admin): persist upstream status changes into selector
handle (#6528)
eb7428279f is described below
commit eb7428279f4d44fa9076073157686a21d0a74100
Author: Duansg <[email protected]>
AuthorDate: Wed Sep 30 09:28:23 2026 +0800
fix(admin): persist upstream status changes into selector handle (#6528)
* fix(admin): persist upstream status changes into selector handle
* supplementary repair
---------
Co-authored-by: aias00 <[email protected]>
---
.../AbstractShenyuClientRegisterServiceImpl.java | 18 +++++++
.../ShenyuClientRegisterDivideServiceImpl.java | 1 +
.../ShenyuClientRegisterDubboServiceImpl.java | 1 +
.../ShenyuClientRegisterGrpcServiceImpl.java | 1 +
.../ShenyuClientRegisterTarsServiceImpl.java | 1 +
.../ShenyuClientRegisterWebSocketServiceImpl.java | 13 +++--
.../ShenyuClientRegisterDivideServiceImplTest.java | 54 +++++++++++++++++++++
.../ShenyuClientRegisterDubboServiceImplTest.java | 56 ++++++++++++++++++++++
.../ShenyuClientRegisterGrpcServiceImplTest.java | 55 +++++++++++++++++++++
.../ShenyuClientRegisterTarsServiceImplTest.java | 54 +++++++++++++++++++++
...enyuClientRegisterWebSocketServiceImplTest.java | 31 ++++++++++++
11 files changed, 280 insertions(+), 5 deletions(-)
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/AbstractShenyuClientRegisterServiceImpl.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/AbstractShenyuClientRegisterServiceImpl.java
index 167383a12c..c4b95a939b 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/AbstractShenyuClientRegisterServiceImpl.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/AbstractShenyuClientRegisterServiceImpl.java
@@ -363,6 +363,24 @@ public abstract class
AbstractShenyuClientRegisterServiceImpl extends FallbackSh
.toList().stream().findAny().orElse(false);
}
+ /**
+ * Sync the changed status back to the exist list, so that the status
change
+ * can be persisted into the selector handle.
+ *
+ * <p>The upstream {@code equals} methods only compare the identity
fields, so an upstream whose
+ * status just changed is still regarded as an existing one and keeps its
old status in the exist list.
+ *
+ * @param existList the upstream list parsed from the selector handle
+ * @param diffStatusList the upstream list whose status has changed
+ * @param <T> the upstream type
+ */
+ protected <T extends CommonUpstream> void syncUpstreamStatus(final List<T>
existList, final List<T> diffStatusList) {
+ for (T changed : diffStatusList) {
+ existList.stream().filter(exist -> exist.equals(changed))
+ .forEach(exist -> exist.setStatus(changed.isStatus()));
+ }
+ }
+
/**
* Build context path default rule dto rule dto.
*
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDivideServiceImpl.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDivideServiceImpl.java
index b83de054b7..956a592027 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDivideServiceImpl.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDivideServiceImpl.java
@@ -92,6 +92,7 @@ public class ShenyuClientRegisterDivideServiceImpl extends
AbstractContextPathRe
|| existList.stream().anyMatch(e -> e.equals(upstream) &&
e.isStatus() != upstream.isStatus())).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(diffStatusList)) {
canAddList.addAll(diffStatusList);
+ syncUpstreamStatus(existList, diffStatusList);
}
}
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDubboServiceImpl.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDubboServiceImpl.java
index 86eefa9a32..51d84e8f8f 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDubboServiceImpl.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDubboServiceImpl.java
@@ -84,6 +84,7 @@ public class ShenyuClientRegisterDubboServiceImpl extends
AbstractShenyuClientRe
|| existList.stream().anyMatch(e -> e.equals(upstream) &&
e.isStatus() != upstream.isStatus())).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(diffStatusList)) {
canAddList.addAll(diffStatusList);
+ syncUpstreamStatus(existList, diffStatusList);
}
}
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterGrpcServiceImpl.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterGrpcServiceImpl.java
index d6983bcd13..0088e2a19b 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterGrpcServiceImpl.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterGrpcServiceImpl.java
@@ -107,6 +107,7 @@ public class ShenyuClientRegisterGrpcServiceImpl extends
AbstractShenyuClientReg
|| existList.stream().anyMatch(e -> e.equals(upstream) &&
e.isStatus() != upstream.isStatus())).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(diffStatusList)) {
canAddList.addAll(diffStatusList);
+ syncUpstreamStatus(existList, diffStatusList);
}
}
if (doSubmit(selectorDO.getId(), canAddList)) {
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterTarsServiceImpl.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterTarsServiceImpl.java
index 2f6fd65b66..7fe50a1a02 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterTarsServiceImpl.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterTarsServiceImpl.java
@@ -88,6 +88,7 @@ public class ShenyuClientRegisterTarsServiceImpl extends
AbstractShenyuClientReg
|| existList.stream().anyMatch(e -> e.equals(upstream) &&
e.isStatus() != upstream.isStatus())).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(diffStatusList)) {
canAddList.addAll(diffStatusList);
+ syncUpstreamStatus(existList, diffStatusList);
}
}
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterWebSocketServiceImpl.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterWebSocketServiceImpl.java
index 7787bc73a5..7fe74ff867 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterWebSocketServiceImpl.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterWebSocketServiceImpl.java
@@ -76,23 +76,26 @@ public class ShenyuClientRegisterWebSocketServiceImpl
extends AbstractContextPat
@Override
protected String buildHandle(final List<URIRegisterDTO> uriList, final
SelectorDO selectorDO) {
- String handleAdd;
List<WebSocketUpstream> addList = buildWebSocketUpstreamList(uriList);
List<WebSocketUpstream> canAddList = new CopyOnWriteArrayList<>();
List<WebSocketUpstream> existList =
GsonUtils.getInstance().fromCurrentList(selectorDO.getHandle(),
WebSocketUpstream.class);
if (CollectionUtils.isEmpty(existList)) {
- handleAdd = GsonUtils.getInstance().toJson(addList);
canAddList = addList;
} else {
- List<WebSocketUpstream> diffList =
addList.stream().filter(divideUpstream ->
!existList.contains(divideUpstream)).collect(Collectors.toList());
+ List<WebSocketUpstream> diffList =
addList.stream().filter(upstream ->
!existList.contains(upstream)).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(diffList)) {
canAddList.addAll(diffList);
existList.addAll(diffList);
}
- handleAdd = GsonUtils.getInstance().toJson(existList);
+ List<WebSocketUpstream> diffStatusList =
addList.stream().filter(upstream -> !upstream.isStatus()
+ || existList.stream().anyMatch(e -> e.equals(upstream) &&
e.isStatus() != upstream.isStatus())).collect(Collectors.toList());
+ if (CollectionUtils.isNotEmpty(diffStatusList)) {
+ canAddList.addAll(diffStatusList);
+ syncUpstreamStatus(existList, diffStatusList);
+ }
}
doSubmit(selectorDO.getId(), canAddList);
- return handleAdd;
+ return
GsonUtils.getInstance().toJson(CollectionUtils.isEmpty(existList) ? canAddList
: existList);
}
private List<WebSocketUpstream> buildWebSocketUpstreamList(final
List<URIRegisterDTO> uriList) {
diff --git
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDivideServiceImplTest.java
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDivideServiceImplTest.java
index cda0c97b44..efcd909407 100644
---
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDivideServiceImplTest.java
+++
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDivideServiceImplTest.java
@@ -29,6 +29,7 @@ import org.apache.shenyu.common.exception.ShenyuException;
import org.apache.shenyu.common.utils.GsonUtils;
import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.apache.shenyu.register.common.enums.EventType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -43,6 +44,8 @@ import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -132,6 +135,57 @@ public final class
ShenyuClientRegisterDivideServiceImplTest {
assertEquals(resultList.size(), 1);
}
+ /**
+ * The status change of an existing upstream should be written back into
the selector handle.
+ * see <a href="https://github.com/apache/shenyu/issues/6522">issue
#6522</a>
+ */
+ @Test
+ public void testBuildHandleWithStatusChanged() {
+ shenyuClientRegisterDivideService =
spy(shenyuClientRegisterDivideService);
+
+ final String returnStr =
"[{protocol:'http://',upstreamHost:'localhost',upstreamUrl:'localhost:8090',warmup:10,weight:50,status:true,timestamp:1637826588267,\"gray\":false},"
+ +
"{protocol:'http://',upstreamHost:'localhost',upstreamUrl:'localhost:8091',warmup:10,weight:50,status:true,timestamp:1637826588267,\"gray\":false}]";
+
+ List<URIRegisterDTO> list = new ArrayList<>();
+
list.add(URIRegisterDTO.builder().protocol("http://").appName("test1").rpcType(RpcTypeEnum.HTTP.getName())
+
.host(LOCALHOST).port(8090).eventType(EventType.DELETED).build());
+ SelectorDO selectorDO = mock(SelectorDO.class);
+ when(selectorDO.getHandle()).thenReturn(returnStr);
+
doReturn(false).when(shenyuClientRegisterDivideService).doSubmit(any(), any());
+ String actual = shenyuClientRegisterDivideService.buildHandle(list,
selectorDO);
+
+ List<DivideUpstream> resultList =
GsonUtils.getInstance().fromCurrentList(actual, DivideUpstream.class);
+ assertEquals(2, resultList.size());
+ assertFalse(resultList.get(0).isStatus());
+ assertTrue(resultList.get(1).isStatus());
+ }
+
+ /**
+ * An offline upstream coming back online should be written back into the
selector handle as well,
+ * and only the re-registered one should be touched.
+ * see <a href="https://github.com/apache/shenyu/issues/6522">issue
#6522</a>
+ */
+ @Test
+ public void testBuildHandleWithStatusRecovered() {
+ shenyuClientRegisterDivideService =
spy(shenyuClientRegisterDivideService);
+
+ final String returnStr =
"[{protocol:'http://',upstreamHost:'localhost',upstreamUrl:'localhost:8090',warmup:10,weight:50,status:false,timestamp:1637826588267,\"gray\":false},"
+ +
"{protocol:'http://',upstreamHost:'localhost',upstreamUrl:'localhost:8091',warmup:10,weight:50,status:false,timestamp:1637826588267,\"gray\":false}]";
+
+ List<URIRegisterDTO> list = new ArrayList<>();
+
list.add(URIRegisterDTO.builder().protocol("http://").appName("test1").rpcType(RpcTypeEnum.HTTP.getName())
+ .host(LOCALHOST).port(8090).build());
+ SelectorDO selectorDO = mock(SelectorDO.class);
+ when(selectorDO.getHandle()).thenReturn(returnStr);
+
doReturn(false).when(shenyuClientRegisterDivideService).doSubmit(any(), any());
+ String actual = shenyuClientRegisterDivideService.buildHandle(list,
selectorDO);
+
+ List<DivideUpstream> resultList =
GsonUtils.getInstance().fromCurrentList(actual, DivideUpstream.class);
+ assertEquals(2, resultList.size());
+ assertTrue(resultList.get(0).isStatus());
+ assertFalse(resultList.get(1).isStatus());
+ }
+
@Test
public void testBuildDivideUpstreamList() {
List<URIRegisterDTO> list = new ArrayList<>();
diff --git
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDubboServiceImplTest.java
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDubboServiceImplTest.java
index d81f2c973b..00445e26ad 100644
---
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDubboServiceImplTest.java
+++
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterDubboServiceImplTest.java
@@ -29,6 +29,7 @@ import org.apache.shenyu.common.exception.ShenyuException;
import org.apache.shenyu.common.utils.GsonUtils;
import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.apache.shenyu.register.common.enums.EventType;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
@@ -42,6 +43,8 @@ import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -135,6 +138,59 @@ public final class
ShenyuClientRegisterDubboServiceImplTest {
assertEquals(resultList.size(), 1);
}
+ /**
+ * The status change of an existing upstream should be written back into
the selector handle.
+ * see <a href="https://github.com/apache/shenyu/issues/6522">issue
#6522</a>
+ */
+ @Test
+ public void testBuildHandleWithStatusChanged() {
+ shenyuClientRegisterDubboService =
spy(shenyuClientRegisterDubboService);
+
+ final String returnStr =
"[{protocol:'dubbo://',upstreamHost:'localhost',upstreamUrl:'localhost:8090',warmup:10,weight:50,status:true,timestamp:1637826588267,\"gray\":false},"
+ +
"{protocol:'dubbo://',upstreamHost:'localhost',upstreamUrl:'localhost:8091',warmup:10,weight:50,status:true,timestamp:1637826588267,\"gray\":false}]";
+
+ List<URIRegisterDTO> list = new ArrayList<>();
+ list.add(URIRegisterDTO.builder().appName("test1")
+ .rpcType(RpcTypeEnum.DUBBO.getName())
+
.host(LOCALHOST).port(8090).eventType(EventType.DELETED).build());
+ SelectorDO selectorDO = mock(SelectorDO.class);
+ when(selectorDO.getHandle()).thenReturn(returnStr);
+ doReturn(false).when(shenyuClientRegisterDubboService).doSubmit(any(),
any());
+ String actual = shenyuClientRegisterDubboService.buildHandle(list,
selectorDO);
+
+ List<DubboUpstream> resultList =
GsonUtils.getInstance().fromCurrentList(actual, DubboUpstream.class);
+ assertEquals(2, resultList.size());
+ assertFalse(resultList.get(0).isStatus());
+ assertTrue(resultList.get(1).isStatus());
+ }
+
+ /**
+ * An offline upstream coming back online should be written back into the
selector handle as well,
+ * and only the re-registered one should be touched.
+ * see <a href="https://github.com/apache/shenyu/issues/6522">issue
#6522</a>
+ */
+ @Test
+ public void testBuildHandleWithStatusRecovered() {
+ shenyuClientRegisterDubboService =
spy(shenyuClientRegisterDubboService);
+
+ final String returnStr =
"[{protocol:'dubbo://',upstreamHost:'localhost',upstreamUrl:'localhost:8090',warmup:10,weight:50,status:false,timestamp:1637826588267,\"gray\":false},"
+ +
"{protocol:'dubbo://',upstreamHost:'localhost',upstreamUrl:'localhost:8091',warmup:10,weight:50,status:false,timestamp:1637826588267,\"gray\":false}]";
+
+ List<URIRegisterDTO> list = new ArrayList<>();
+ list.add(URIRegisterDTO.builder().appName("test1")
+ .rpcType(RpcTypeEnum.DUBBO.getName())
+ .host(LOCALHOST).port(8090).build());
+ SelectorDO selectorDO = mock(SelectorDO.class);
+ when(selectorDO.getHandle()).thenReturn(returnStr);
+ doReturn(false).when(shenyuClientRegisterDubboService).doSubmit(any(),
any());
+ String actual = shenyuClientRegisterDubboService.buildHandle(list,
selectorDO);
+
+ List<DubboUpstream> resultList =
GsonUtils.getInstance().fromCurrentList(actual, DubboUpstream.class);
+ assertEquals(2, resultList.size());
+ assertTrue(resultList.get(0).isStatus());
+ assertFalse(resultList.get(1).isStatus());
+ }
+
@Test
public void testBuildDivideUpstreamList() {
List<URIRegisterDTO> list = new ArrayList<>();
diff --git
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterGrpcServiceImplTest.java
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterGrpcServiceImplTest.java
index 7e731fadb8..bc53b41d8d 100644
---
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterGrpcServiceImplTest.java
+++
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterGrpcServiceImplTest.java
@@ -21,12 +21,14 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.shenyu.admin.model.entity.MetaDataDO;
import org.apache.shenyu.admin.model.entity.SelectorDO;
import org.apache.shenyu.admin.service.impl.MetaDataServiceImpl;
+import org.apache.shenyu.common.dto.convert.selector.GrpcUpstream;
import org.apache.shenyu.common.dto.convert.selector.TarsUpstream;
import org.apache.shenyu.common.enums.RpcTypeEnum;
import org.apache.shenyu.common.exception.ShenyuException;
import org.apache.shenyu.common.utils.GsonUtils;
import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.apache.shenyu.register.common.enums.EventType;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
@@ -41,6 +43,8 @@ import java.util.List;
import static
org.apache.shenyu.common.constant.Constants.SYS_DEFAULT_NAMESPACE_ID;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -130,6 +134,57 @@ public final class ShenyuClientRegisterGrpcServiceImplTest
{
assertEquals(resultList.size(), 1);
}
+ /**
+ * The status change of an existing upstream should be written back into
the selector handle.
+ * see <a href="https://github.com/apache/shenyu/issues/6522">issue
#6522</a>
+ */
+ @Test
+ public void testBuildHandleWithStatusChanged() {
+ shenyuClientRegisterGrpcService = spy(shenyuClientRegisterGrpcService);
+
+ final String returnStr =
"[{upstreamUrl='localhost:8090',weight=1,status=true,timestamp=1637826588267,\"gray\":false},"
+ +
"{upstreamUrl='localhost:8091',weight=2,status=true,timestamp=1637826588267,\"gray\":false}]";
+
+ List<URIRegisterDTO> list = new ArrayList<>();
+
list.add(URIRegisterDTO.builder().appName("test1").rpcType(RpcTypeEnum.GRPC.getName())
+
.host("localhost").port(8090).eventType(EventType.DELETED).build());
+ SelectorDO selectorDO = mock(SelectorDO.class);
+ when(selectorDO.getHandle()).thenReturn(returnStr);
+ doReturn(false).when(shenyuClientRegisterGrpcService).doSubmit(any(),
any());
+ String actual = shenyuClientRegisterGrpcService.buildHandle(list,
selectorDO);
+
+ List<GrpcUpstream> resultList =
GsonUtils.getInstance().fromCurrentList(actual, GrpcUpstream.class);
+ assertEquals(2, resultList.size());
+ assertFalse(resultList.get(0).isStatus());
+ assertTrue(resultList.get(1).isStatus());
+ }
+
+ /**
+ * An offline upstream coming back online should be written back into the
selector handle as well,
+ * and only the re-registered one should be touched.
+ * see <a href="https://github.com/apache/shenyu/issues/6522">issue
#6522</a>
+ */
+ @Test
+ public void testBuildHandleWithStatusRecovered() {
+ shenyuClientRegisterGrpcService = spy(shenyuClientRegisterGrpcService);
+
+ final String returnStr =
"[{upstreamUrl='localhost:8090',weight=1,status=false,timestamp=1637826588267,\"gray\":false},"
+ +
"{upstreamUrl='localhost:8091',weight=2,status=false,timestamp=1637826588267,\"gray\":false}]";
+
+ List<URIRegisterDTO> list = new ArrayList<>();
+
list.add(URIRegisterDTO.builder().appName("test1").rpcType(RpcTypeEnum.GRPC.getName())
+ .host("localhost").port(8090).build());
+ SelectorDO selectorDO = mock(SelectorDO.class);
+ when(selectorDO.getHandle()).thenReturn(returnStr);
+ doReturn(false).when(shenyuClientRegisterGrpcService).doSubmit(any(),
any());
+ String actual = shenyuClientRegisterGrpcService.buildHandle(list,
selectorDO);
+
+ List<GrpcUpstream> resultList =
GsonUtils.getInstance().fromCurrentList(actual, GrpcUpstream.class);
+ assertEquals(2, resultList.size());
+ assertTrue(resultList.get(0).isStatus());
+ assertFalse(resultList.get(1).isStatus());
+ }
+
@Test
public void testBuildGrpcUpstreamList() {
List<URIRegisterDTO> list = new ArrayList<>();
diff --git
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterTarsServiceImplTest.java
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterTarsServiceImplTest.java
index 8b3c264dbe..eea20536a9 100644
---
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterTarsServiceImplTest.java
+++
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterTarsServiceImplTest.java
@@ -27,6 +27,7 @@ import org.apache.shenyu.common.exception.ShenyuException;
import org.apache.shenyu.common.utils.GsonUtils;
import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.apache.shenyu.register.common.enums.EventType;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
@@ -41,6 +42,8 @@ import java.util.List;
import static
org.apache.shenyu.common.constant.Constants.SYS_DEFAULT_NAMESPACE_ID;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -132,6 +135,57 @@ public final class ShenyuClientRegisterTarsServiceImplTest
{
assertEquals(resultList.size(), 1);
}
+ /**
+ * The status change of an existing upstream should be written back into
the selector handle.
+ * see <a href="https://github.com/apache/shenyu/issues/6522">issue
#6522</a>
+ */
+ @Test
+ public void testBuildHandleWithStatusChanged() {
+ shenyuClientRegisterTarsService = spy(shenyuClientRegisterTarsService);
+
+ final String returnStr =
"[{upstreamUrl:'localhost:8090',weight:1,warmup:10,status:true,timestamp:1637826588267,\"gray\":false},"
+ +
"{upstreamUrl:'localhost:8091',weight:2,warmup:10,status:true,timestamp:1637826588267,\"gray\":false}]";
+
+ List<URIRegisterDTO> list = new ArrayList<>();
+
list.add(URIRegisterDTO.builder().appName("test1").rpcType(RpcTypeEnum.TARS.getName())
+
.host("localhost").port(8090).eventType(EventType.DELETED).build());
+ SelectorDO selectorDO = mock(SelectorDO.class);
+ when(selectorDO.getHandle()).thenReturn(returnStr);
+ doReturn(false).when(shenyuClientRegisterTarsService).doSubmit(any(),
any());
+ String actual = shenyuClientRegisterTarsService.buildHandle(list,
selectorDO);
+
+ List<TarsUpstream> resultList =
GsonUtils.getInstance().fromCurrentList(actual, TarsUpstream.class);
+ assertEquals(2, resultList.size());
+ assertFalse(resultList.get(0).isStatus());
+ assertTrue(resultList.get(1).isStatus());
+ }
+
+ /**
+ * An offline upstream coming back online should be written back into the
selector handle as well,
+ * and only the re-registered one should be touched.
+ * see <a href="https://github.com/apache/shenyu/issues/6522">issue
#6522</a>
+ */
+ @Test
+ public void testBuildHandleWithStatusRecovered() {
+ shenyuClientRegisterTarsService = spy(shenyuClientRegisterTarsService);
+
+ final String returnStr =
"[{upstreamUrl:'localhost:8090',weight:1,warmup:10,status:false,timestamp:1637826588267,\"gray\":false},"
+ +
"{upstreamUrl:'localhost:8091',weight:2,warmup:10,status:false,timestamp:1637826588267,\"gray\":false}]";
+
+ List<URIRegisterDTO> list = new ArrayList<>();
+
list.add(URIRegisterDTO.builder().appName("test1").rpcType(RpcTypeEnum.TARS.getName())
+ .host("localhost").port(8090).build());
+ SelectorDO selectorDO = mock(SelectorDO.class);
+ when(selectorDO.getHandle()).thenReturn(returnStr);
+ doReturn(false).when(shenyuClientRegisterTarsService).doSubmit(any(),
any());
+ String actual = shenyuClientRegisterTarsService.buildHandle(list,
selectorDO);
+
+ List<TarsUpstream> resultList =
GsonUtils.getInstance().fromCurrentList(actual, TarsUpstream.class);
+ assertEquals(2, resultList.size());
+ assertTrue(resultList.get(0).isStatus());
+ assertFalse(resultList.get(1).isStatus());
+ }
+
@Test
public void testBuildTarsUpstreamList() {
List<URIRegisterDTO> list = new ArrayList<>();
diff --git
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterWebSocketServiceImplTest.java
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterWebSocketServiceImplTest.java
index 3da5ab7cc8..2296d22e71 100644
---
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterWebSocketServiceImplTest.java
+++
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/register/ShenyuClientRegisterWebSocketServiceImplTest.java
@@ -37,10 +37,14 @@ import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import static
org.apache.shenyu.common.constant.Constants.SYS_DEFAULT_NAMESPACE_ID;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -127,4 +131,31 @@ class ShenyuClientRegisterWebSocketServiceImplTest {
assertEquals(webSocketUpstreamResult.get("upstreamHost"), "localhost");
assertEquals(webSocketUpstreamResult.get("status"), true);
}
+
+ /**
+ * An offline upstream coming back online should be written back into the
selector handle as well,
+ * and only the re-registered one should be touched.
+ * see <a href="https://github.com/apache/shenyu/issues/6522">issue
#6522</a>
+ */
+ @Test
+ public void testBuildHandleWithStatusRecovered() {
+ when(upstreamCheckService.checkAndSubmit(any(),
any())).thenReturn(false);
+ SelectorDO selectorDO = new SelectorDO();
+ selectorDO.setHandle(GsonUtils.getInstance().toJson(Arrays.asList(
+ offlineUpstream("host:8080"), offlineUpstream("host:8081"))));
+
+ List<URIRegisterDTO> uriList =
Collections.singletonList(URIRegisterDTO.builder()
+
.protocol("ws://").host("host").port(8080).namespaceId(SYS_DEFAULT_NAMESPACE_ID).build());
+ String actual =
shenyuClientRegisterWebSocketService.buildHandle(uriList, selectorDO);
+
+ List<WebSocketUpstream> resultList =
GsonUtils.getInstance().fromCurrentList(actual, WebSocketUpstream.class);
+ assertEquals(2, resultList.size());
+ assertTrue(resultList.get(0).isStatus());
+ assertFalse(resultList.get(1).isStatus());
+ }
+
+ private static WebSocketUpstream offlineUpstream(final String url) {
+ return
WebSocketUpstream.builder().host("localhost").protocol("ws://").upstreamUrl(url)
+
.weight(50).warmup(10).namespaceId(SYS_DEFAULT_NAMESPACE_ID).status(false).build();
+ }
}