diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosConnectionManager.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosConnectionManager.java index aa684cd7eb..2698e6cd34 100644 --- a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosConnectionManager.java +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosConnectionManager.java @@ -16,7 +16,15 @@ */ package org.apache.dubbo.registry.nacos; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; + import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.constants.LoggerCodeConstants; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.StringUtils; @@ -27,18 +35,13 @@ import com.alibaba.nacos.api.PropertyKeyConst; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.NamingService; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; - import static com.alibaba.nacos.api.PropertyKeyConst.NAMING_LOAD_CACHE_AT_START; import static com.alibaba.nacos.api.PropertyKeyConst.PASSWORD; import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR; import static com.alibaba.nacos.api.PropertyKeyConst.USERNAME; +import static com.alibaba.nacos.client.constant.Constants.HealthCheck.UP; import static com.alibaba.nacos.client.naming.utils.UtilAndComs.NACOS_NAMING_LOG_NAME; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_INTERRUPTED; import static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_NACOS_EXCEPTION; import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY; import static org.apache.dubbo.common.utils.StringConstantFieldValuePredicate.of; @@ -52,8 +55,17 @@ public class NacosConnectionManager { private final List namingServiceList = new LinkedList<>(); - public NacosConnectionManager(URL connectionURL) { + private final int retryTimes; + + private final int sleepMsBetweenRetries; + + private final boolean check; + + public NacosConnectionManager(URL connectionURL, boolean check, int retryTimes, int sleepMsBetweenRetries) { this.connectionURL = connectionURL; + this.check = check; + this.retryTimes = retryTimes; + this.sleepMsBetweenRetries = sleepMsBetweenRetries; // create default one this.namingServiceList.add(createNamingService()); } @@ -64,6 +76,9 @@ public class NacosConnectionManager { @Deprecated protected NacosConnectionManager(NamingService namingService) { this.connectionURL = null; + this.retryTimes = 0; + this.sleepMsBetweenRetries = 0; + this.check = false; // create default one this.namingServiceList.add(namingService); } @@ -103,15 +118,37 @@ public class NacosConnectionManager { */ protected NamingService createNamingService() { Properties nacosProperties = buildNacosProperties(this.connectionURL); - NamingService namingService; + NamingService namingService = null; try { - namingService = NacosFactory.createNamingService(nacosProperties); + for (int i = 0; i < retryTimes + 1; i++) { + namingService = NacosFactory.createNamingService(nacosProperties); + if (!check || UP.equals(namingService.getServerStatus())) { + break; + } else { + logger.warn(LoggerCodeConstants.REGISTRY_NACOS_EXCEPTION, "", "", + "Failed to connect to nacos naming server. " + + (i < retryTimes ? "Dubbo will try to retry in " + sleepMsBetweenRetries + ". " : "Exceed retry max times.") + + "Try times: " + (i + 1)); + } + namingService.shutDown(); + namingService = null; + Thread.sleep(sleepMsBetweenRetries); + } } catch (NacosException e) { if (logger.isErrorEnabled()) { logger.error(REGISTRY_NACOS_EXCEPTION, "", "", e.getErrMsg(), e); } + } catch (InterruptedException e) { + logger.error(INTERNAL_INTERRUPTED, "", "", "Interrupted when creating nacos naming service client.", e); + Thread.currentThread().interrupt(); throw new IllegalStateException(e); } + + if (namingService == null) { + logger.error(REGISTRY_NACOS_EXCEPTION, "", "", "Failed to create nacos naming service client. Reason: server status check failed."); + throw new IllegalStateException("Failed to create nacos naming service client. Reason: server status check failed."); + } + return namingService; } diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosNamingServiceWrapper.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosNamingServiceWrapper.java index cfa45b66f9..1b41428dc6 100644 --- a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosNamingServiceWrapper.java +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosNamingServiceWrapper.java @@ -416,7 +416,7 @@ public class NacosNamingServiceWrapper { logger.warn(LoggerCodeConstants.REGISTRY_NACOS_EXCEPTION, "", "", "Failed to request nacos naming server. " + (times < retryTimes ? "Dubbo will try to retry in " + sleepMsBetweenRetries + ". " : "Exceed retry max times.") + - "Try times: " + times + 1, e); + "Try times: " + (times + 1), e); if (times < retryTimes) { try { Thread.sleep(sleepMsBetweenRetries); @@ -450,7 +450,7 @@ public class NacosNamingServiceWrapper { logger.warn(LoggerCodeConstants.REGISTRY_NACOS_EXCEPTION, "", "", "Failed to request nacos naming server. " + (times < retryTimes ? "Dubbo will try to retry in " + sleepMsBetweenRetries + ". " : "Exceed retry max times.") + - "Try times: " + times + 1, e); + "Try times: " + (times + 1), e); if (times < retryTimes) { try { Thread.sleep(sleepMsBetweenRetries); diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/util/NacosNamingServiceUtils.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/util/NacosNamingServiceUtils.java index 0b02dba552..f594e473d0 100644 --- a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/util/NacosNamingServiceUtils.java +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/util/NacosNamingServiceUtils.java @@ -46,6 +46,8 @@ public class NacosNamingServiceUtils { private static final String NACOS_RETRY_WAIT_KEY = "nacos.retry-wait"; + private static final String NACOS_CHECK_KEY = "nacos.check"; + private NacosNamingServiceUtils() { throw new IllegalStateException("NacosNamingServiceUtils should not be instantiated"); } @@ -108,8 +110,10 @@ public class NacosNamingServiceUtils { * @since 2.7.5 */ public static NacosNamingServiceWrapper createNamingService(URL connectionURL) { - int retryTimes = connectionURL.getParameter(NACOS_RETRY_KEY, 10); - int sleepMsBetweenRetries = connectionURL.getParameter(NACOS_RETRY_WAIT_KEY, 10); - return new NacosNamingServiceWrapper(new NacosConnectionManager(connectionURL), retryTimes, sleepMsBetweenRetries); + boolean check = connectionURL.getParameter(NACOS_CHECK_KEY, true); + int retryTimes = connectionURL.getPositiveParameter(NACOS_RETRY_KEY, 10); + int sleepMsBetweenRetries = connectionURL.getPositiveParameter(NACOS_RETRY_WAIT_KEY, 10); + NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(connectionURL, check, retryTimes, sleepMsBetweenRetries); + return new NacosNamingServiceWrapper(nacosConnectionManager, retryTimes, sleepMsBetweenRetries); } } diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosConnectionsManagerTest.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosConnectionsManagerTest.java index 53f1ade39a..1f6f30145c 100644 --- a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosConnectionsManagerTest.java +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosConnectionsManagerTest.java @@ -16,17 +16,26 @@ */ package org.apache.dubbo.registry.nacos; -import org.apache.dubbo.common.URL; - -import com.alibaba.nacos.api.naming.NamingService; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.dubbo.common.URL; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingService; + +import static com.alibaba.nacos.client.constant.Constants.HealthCheck.DOWN; +import static com.alibaba.nacos.client.constant.Constants.HealthCheck.UP; +import static org.mockito.ArgumentMatchers.any; public class NacosConnectionsManagerTest { @Test @@ -41,7 +50,7 @@ public class NacosConnectionsManagerTest { @Test public void testCreate() { List namingServiceList = new ArrayList<>(); - NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf("")) { + NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf(""), false, 0, 0) { @Override protected NamingService createNamingService() { NamingService namingService = Mockito.mock(NamingService.class); @@ -81,4 +90,47 @@ public class NacosConnectionsManagerTest { copy = new LinkedList<>(namingServiceList); Assertions.assertFalse(copy.contains(nacosConnectionManager.getNamingService())); } + + @Test + void testRetryCreate() throws NacosException { + try (MockedStatic nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) { + AtomicInteger atomicInteger = new AtomicInteger(0); + NamingService mock = new MockNamingService() { + @Override + public String getServerStatus() { + return atomicInteger.incrementAndGet() > 10 ? UP : DOWN; + } + }; + nacosFactoryMockedStatic.when(() -> NacosFactory.createNamingService((Properties) any())).thenReturn(mock); + + URL url = URL.valueOf("nacos://127.0.0.1:8848"); + Assertions.assertThrows(IllegalStateException.class, () -> new NacosConnectionManager(url, true, 5, 10)); + + try { + new NacosConnectionManager(url, true, 5, 10); + } catch (Throwable t) { + Assertions.fail(t); + } + } + } + @Test + void testNoCheck() throws NacosException { + try (MockedStatic nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) { + NamingService mock = new MockNamingService() { + @Override + public String getServerStatus() { + return DOWN; + } + }; + nacosFactoryMockedStatic.when(() -> NacosFactory.createNamingService((Properties) any())).thenReturn(mock); + + URL url = URL.valueOf("nacos://127.0.0.1:8848"); + + try { + new NacosConnectionManager(url, false, 5, 10); + } catch (Throwable t) { + Assertions.fail(t); + } + } + } } diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosNamingServiceWrapperTest.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosNamingServiceWrapperTest.java index ea7f44a049..7fcf7f47f1 100644 --- a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosNamingServiceWrapperTest.java +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosNamingServiceWrapperTest.java @@ -91,7 +91,7 @@ class NacosNamingServiceWrapperTest { @Test void testRegisterNacos2_0_x() throws NacosException { List namingServiceList = new LinkedList<>(); - NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf("")) { + NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf(""), false, 0, 0) { @Override protected NamingService createNamingService() { NamingService namingService = Mockito.mock(NamingService.class); @@ -140,7 +140,7 @@ class NacosNamingServiceWrapperTest { @Test void testRegisterNacos2_1_xClient2_0_xServer() throws NacosException { List namingServiceList = new LinkedList<>(); - NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf("")) { + NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf(""), false, 0, 0) { @Override protected NamingService createNamingService() { NamingService namingService = Mockito.mock(NamingService.class); @@ -204,7 +204,7 @@ class NacosNamingServiceWrapperTest { @Test void testRegisterNacos2_1_xClient2_1_xServer() throws NacosException { List namingServiceList = new LinkedList<>(); - NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf("")) { + NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf(""), false, 0, 0) { @Override protected NamingService createNamingService() { NamingService namingService = Mockito.mock(NamingService.class); @@ -307,7 +307,7 @@ class NacosNamingServiceWrapperTest { @Test void testUnregister() throws NacosException { List namingServiceList = new LinkedList<>(); - NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf("")) { + NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf(""), false, 0, 0) { @Override protected NamingService createNamingService() { NamingService namingService = Mockito.mock(NamingService.class);