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

albumenj pushed a commit to branch 3.1
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.1 by this push:
     new 673375b9bf Add nacos create client retry (#11304)
673375b9bf is described below

commit 673375b9bf3200b23b52aaa84eab61ee148d6f6e
Author: Albumen Kevin <[email protected]>
AuthorDate: Sat Jan 14 21:41:07 2023 +0800

    Add nacos create client retry (#11304)
---
 .../support/nacos/NacosDynamicConfiguration.java   | 59 +++++++++++----
 .../support/nacos/MockConfigService.java           | 78 ++++++++++++++++++++
 .../configcenter/support/nacos/RetryTest.java      | 86 ++++++++++++++++++++++
 .../metadata/store/nacos/NacosMetadataReport.java  | 73 +++++++++++++-----
 .../metadata/store/nacos/MockConfigService.java    | 78 ++++++++++++++++++++
 .../dubbo/metadata/store/nacos/RetryTest.java      | 85 +++++++++++++++++++++
 .../registry/nacos/NacosNamingServiceWrapper.java  |  4 +-
 .../nacos/util/NacosNamingServiceUtils.java        | 41 +++++++++--
 .../registry/nacos/NacosRegistryFactoryTest.java   |  5 +-
 .../dubbo/registry/nacos/NacosRegistryTest.java    |  2 +-
 .../nacos/NacosServiceDiscoveryFactoryTest.java    |  3 +-
 .../registry/nacos/NacosServiceDiscoveryTest.java  | 26 +++----
 .../nacos/util/NacosNamingServiceUtilsTest.java    | 47 ++++++++++--
 13 files changed, 523 insertions(+), 64 deletions(-)

diff --git 
a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
 
b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
index 2f43c85f27..beb2400860 100644
--- 
a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
+++ 
b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
@@ -17,12 +17,20 @@
 
 package org.apache.dubbo.configcenter.support.nacos;
 
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.Executor;
+
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
 import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
 import org.apache.dubbo.common.config.configcenter.ConfigItem;
 import org.apache.dubbo.common.config.configcenter.ConfigurationListener;
 import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
+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.MD5Utils;
@@ -34,17 +42,12 @@ import com.alibaba.nacos.api.config.ConfigService;
 import com.alibaba.nacos.api.config.listener.AbstractSharedListener;
 import com.alibaba.nacos.api.exception.NacosException;
 
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.Executor;
-
 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 
org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_ERROR_NACOS;
+import static 
org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_INTERRUPTED;
 import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;
 import static 
org.apache.dubbo.common.utils.StringConstantFieldValuePredicate.of;
 import static org.apache.dubbo.common.utils.StringUtils.HYPHEN_CHAR;
@@ -64,6 +67,12 @@ public class NacosDynamicConfiguration implements 
DynamicConfiguration {
 
     private Properties nacosProperties;
 
+    private static final String NACOS_RETRY_KEY = "nacos.retry";
+
+    private static final String NACOS_RETRY_WAIT_KEY = "nacos.retry-wait";
+
+    private static final String NACOS_CHECK_KEY = "nacos.check";
+
     /**
      * The nacos configService
      */
@@ -83,16 +92,40 @@ public class NacosDynamicConfiguration implements 
DynamicConfiguration {
     }
 
     private NacosConfigServiceWrapper buildConfigService(URL url) {
-        ConfigService configService = null;
+        int retryTimes = url.getPositiveParameter(NACOS_RETRY_KEY, 10);
+        int sleepMsBetweenRetries = 
url.getPositiveParameter(NACOS_RETRY_WAIT_KEY, 1000);
+        boolean check = url.getParameter(NACOS_CHECK_KEY, true);
+        ConfigService tmpConfigServices = null;
         try {
-            configService = NacosFactory.createConfigService(nacosProperties);
-        } catch (NacosException e) {
-            if (logger.isErrorEnabled()) {
-                logger.error(CONFIG_ERROR_NACOS, "", "", e.getMessage(), e);
+            for (int i = 0; i < retryTimes + 1; i++) {
+                tmpConfigServices = 
NacosFactory.createConfigService(nacosProperties);
+                if (!check || UP.equals(tmpConfigServices.getServerStatus())) {
+                    break;
+                } else {
+                    logger.warn(LoggerCodeConstants.CONFIG_ERROR_NACOS, "", "",
+                        "Failed to connect to nacos config server. " +
+                            (i < retryTimes ? "Dubbo will try to retry in " + 
sleepMsBetweenRetries + ". " : "Exceed retry max times.") +
+                            "Try times: " + (i + 1));
+                }
+                tmpConfigServices.shutDown();
+                tmpConfigServices = null;
+                Thread.sleep(sleepMsBetweenRetries);
             }
+        } catch (NacosException e) {
+            logger.error(CONFIG_ERROR_NACOS, "", "", e.getErrMsg(), e);
+            throw new IllegalStateException(e);
+        } catch (InterruptedException e) {
+            logger.error(INTERNAL_INTERRUPTED, "", "", "Interrupted when 
creating nacos config service client.", e);
+            Thread.currentThread().interrupt();
             throw new IllegalStateException(e);
         }
-        return new NacosConfigServiceWrapper(configService);
+
+        if (tmpConfigServices == null) {
+            logger.error(CONFIG_ERROR_NACOS, "", "", "Failed to create nacos 
config service client. Reason: server status check failed.");
+            throw new IllegalStateException("Failed to create nacos config 
service client. Reason: server status check failed.");
+        }
+
+        return new NacosConfigServiceWrapper(tmpConfigServices);
     }
 
     private Properties buildNacosProperties(URL url) {
diff --git 
a/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/MockConfigService.java
 
b/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/MockConfigService.java
new file mode 100644
index 0000000000..bba7741e64
--- /dev/null
+++ 
b/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/MockConfigService.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.dubbo.configcenter.support.nacos;
+
+import com.alibaba.nacos.api.config.ConfigService;
+import com.alibaba.nacos.api.config.listener.Listener;
+import com.alibaba.nacos.api.exception.NacosException;
+
+public class MockConfigService implements ConfigService {
+    @Override
+    public String getConfig(String dataId, String group, long timeoutMs) 
throws NacosException {
+        return null;
+    }
+
+    @Override
+    public String getConfigAndSignListener(String dataId, String group, long 
timeoutMs, Listener listener) throws NacosException {
+        return null;
+    }
+
+    @Override
+    public void addListener(String dataId, String group, Listener listener) 
throws NacosException {
+
+    }
+
+    @Override
+    public boolean publishConfig(String dataId, String group, String content) 
throws NacosException {
+        return false;
+    }
+
+    @Override
+    public boolean publishConfig(String dataId, String group, String content, 
String type) throws NacosException {
+        return false;
+    }
+
+    @Override
+    public boolean publishConfigCas(String dataId, String group, String 
content, String casMd5) throws NacosException {
+        return false;
+    }
+
+    @Override
+    public boolean publishConfigCas(String dataId, String group, String 
content, String casMd5, String type) throws NacosException {
+        return false;
+    }
+
+    @Override
+    public boolean removeConfig(String dataId, String group) throws 
NacosException {
+        return false;
+    }
+
+    @Override
+    public void removeListener(String dataId, String group, Listener listener) 
{
+
+    }
+
+    @Override
+    public String getServerStatus() {
+        return null;
+    }
+
+    @Override
+    public void shutDown() throws NacosException {
+
+    }
+}
diff --git 
a/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/RetryTest.java
 
b/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/RetryTest.java
new file mode 100644
index 0000000000..e90a5cb016
--- /dev/null
+++ 
b/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/RetryTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.dubbo.configcenter.support.nacos;
+
+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.config.ConfigService;
+
+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;
+
+class RetryTest {
+
+    @Test
+    void testRetryCreate() {
+        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = 
Mockito.mockStatic(NacosFactory.class)) {
+            AtomicInteger atomicInteger = new AtomicInteger(0);
+            ConfigService mock = new MockConfigService() {
+                @Override
+                public String getServerStatus() {
+                    return atomicInteger.incrementAndGet() > 10 ? UP : DOWN;
+                }
+            };
+            nacosFactoryMockedStatic.when(() -> 
NacosFactory.createConfigService((Properties) any())).thenReturn(mock);
+
+
+            URL url = URL.valueOf("nacos://127.0.0.1:8848")
+                .addParameter("nacos.retry", 5)
+                .addParameter("nacos.retry-wait", 10);
+            Assertions.assertThrows(IllegalStateException.class, () -> new 
NacosDynamicConfiguration(url));
+
+            try {
+                new NacosDynamicConfiguration(url);
+            } catch (Throwable t) {
+                Assertions.fail(t);
+            }
+        }
+    }
+
+    @Test
+    void testDisable() {
+        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = 
Mockito.mockStatic(NacosFactory.class)) {
+            ConfigService mock = new MockConfigService() {
+                @Override
+                public String getServerStatus() {
+                    return DOWN;
+                }
+            };
+            nacosFactoryMockedStatic.when(() -> 
NacosFactory.createConfigService((Properties) any())).thenReturn(mock);
+
+
+            URL url = URL.valueOf("nacos://127.0.0.1:8848")
+                .addParameter("nacos.retry", 5)
+                .addParameter("nacos.retry-wait", 10)
+                .addParameter("nacos.check", "false");
+            try {
+                new NacosDynamicConfiguration(url);
+            } catch (Throwable t) {
+                Assertions.fail(t);
+            }
+        }
+    }
+}
diff --git 
a/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
 
b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
index 88f65ba642..9d2a93c24a 100644
--- 
a/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
+++ 
b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
@@ -17,11 +17,24 @@
 
 package org.apache.dubbo.metadata.store.nacos;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.Executor;
+
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
 import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
 import org.apache.dubbo.common.config.configcenter.ConfigItem;
 import org.apache.dubbo.common.config.configcenter.ConfigurationListener;
+import org.apache.dubbo.common.constants.LoggerCodeConstants;
 import org.apache.dubbo.common.utils.JsonUtils;
 import org.apache.dubbo.common.utils.MD5Utils;
 import org.apache.dubbo.common.utils.StringUtils;
@@ -38,23 +51,15 @@ import 
org.apache.dubbo.metadata.report.support.AbstractMetadataReport;
 
 import com.alibaba.nacos.api.NacosFactory;
 import com.alibaba.nacos.api.PropertyKeyConst;
+import com.alibaba.nacos.api.config.ConfigService;
 import com.alibaba.nacos.api.config.listener.AbstractSharedListener;
 import com.alibaba.nacos.api.exception.NacosException;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.Executor;
-
 import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
+import static com.alibaba.nacos.client.constant.Constants.HealthCheck.UP;
 import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static 
org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_ERROR_NACOS;
+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;
@@ -81,25 +86,57 @@ public class NacosMetadataReport extends 
AbstractMetadataReport {
 
     private MD5Utils md5Utils = new MD5Utils();
 
+    private static final String NACOS_RETRY_KEY = "nacos.retry";
+
+    private static final String NACOS_RETRY_WAIT_KEY = "nacos.retry-wait";
+
+    private static final String NACOS_CHECK_KEY = "nacos.check";
+
     public NacosMetadataReport(URL url) {
         super(url);
         this.configService = buildConfigService(url);
         group = url.getParameter(GROUP_KEY, DEFAULT_ROOT);
     }
 
-    public NacosConfigServiceWrapper buildConfigService(URL url) {
+    private NacosConfigServiceWrapper buildConfigService(URL url) {
         Properties nacosProperties = buildNacosProperties(url);
+        int retryTimes = url.getPositiveParameter(NACOS_RETRY_KEY, 10);
+        int sleepMsBetweenRetries = 
url.getPositiveParameter(NACOS_RETRY_WAIT_KEY, 1000);
+        boolean check = url.getParameter(NACOS_CHECK_KEY, true);
+        ConfigService tmpConfigServices = null;
         try {
-            configService = new 
NacosConfigServiceWrapper(NacosFactory.createConfigService(nacosProperties));
-        } catch (NacosException e) {
-            if (logger.isErrorEnabled()) {
-                logger.error(REGISTRY_NACOS_EXCEPTION, "", "", e.getErrMsg(), 
e);
+            for (int i = 0; i < retryTimes + 1; i++) {
+                tmpConfigServices = 
NacosFactory.createConfigService(nacosProperties);
+                if (!check || UP.equals(tmpConfigServices.getServerStatus())) {
+                    break;
+                } else {
+                    logger.warn(LoggerCodeConstants.CONFIG_ERROR_NACOS, "", "",
+                        "Failed to connect to nacos config server. " +
+                            (i < retryTimes ? "Dubbo will try to retry in " + 
sleepMsBetweenRetries + ". " : "Exceed retry max times.") +
+                            "Try times: " + (i + 1));
+                }
+                tmpConfigServices.shutDown();
+                tmpConfigServices = null;
+                Thread.sleep(sleepMsBetweenRetries);
             }
+        } catch (NacosException e) {
+            logger.error(CONFIG_ERROR_NACOS, "", "", e.getErrMsg(), e);
+            throw new IllegalStateException(e);
+        } catch (InterruptedException e) {
+            logger.error(INTERNAL_INTERRUPTED, "", "", "Interrupted when 
creating nacos config service client.", e);
+            Thread.currentThread().interrupt();
             throw new IllegalStateException(e);
         }
-        return configService;
+
+        if (tmpConfigServices == null) {
+            logger.error(CONFIG_ERROR_NACOS, "", "", "Failed to create nacos 
config service client. Reason: server status check failed.");
+            throw new IllegalStateException("Failed to create nacos config 
service client. Reason: server status check failed.");
+        }
+
+        return new NacosConfigServiceWrapper(tmpConfigServices);
     }
 
+
     private Properties buildNacosProperties(URL url) {
         Properties properties = new Properties();
         setServerAddr(url, properties);
diff --git 
a/dubbo-metadata/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/MockConfigService.java
 
b/dubbo-metadata/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/MockConfigService.java
new file mode 100644
index 0000000000..86b5b879f7
--- /dev/null
+++ 
b/dubbo-metadata/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/MockConfigService.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.dubbo.metadata.store.nacos;
+
+import com.alibaba.nacos.api.config.ConfigService;
+import com.alibaba.nacos.api.config.listener.Listener;
+import com.alibaba.nacos.api.exception.NacosException;
+
+public class MockConfigService implements ConfigService {
+    @Override
+    public String getConfig(String dataId, String group, long timeoutMs) 
throws NacosException {
+        return null;
+    }
+
+    @Override
+    public String getConfigAndSignListener(String dataId, String group, long 
timeoutMs, Listener listener) throws NacosException {
+        return null;
+    }
+
+    @Override
+    public void addListener(String dataId, String group, Listener listener) 
throws NacosException {
+
+    }
+
+    @Override
+    public boolean publishConfig(String dataId, String group, String content) 
throws NacosException {
+        return false;
+    }
+
+    @Override
+    public boolean publishConfig(String dataId, String group, String content, 
String type) throws NacosException {
+        return false;
+    }
+
+    @Override
+    public boolean publishConfigCas(String dataId, String group, String 
content, String casMd5) throws NacosException {
+        return false;
+    }
+
+    @Override
+    public boolean publishConfigCas(String dataId, String group, String 
content, String casMd5, String type) throws NacosException {
+        return false;
+    }
+
+    @Override
+    public boolean removeConfig(String dataId, String group) throws 
NacosException {
+        return false;
+    }
+
+    @Override
+    public void removeListener(String dataId, String group, Listener listener) 
{
+
+    }
+
+    @Override
+    public String getServerStatus() {
+        return null;
+    }
+
+    @Override
+    public void shutDown() throws NacosException {
+
+    }
+}
diff --git 
a/dubbo-metadata/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/RetryTest.java
 
b/dubbo-metadata/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/RetryTest.java
new file mode 100644
index 0000000000..9159e076fc
--- /dev/null
+++ 
b/dubbo-metadata/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/RetryTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.dubbo.metadata.store.nacos;
+
+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.config.ConfigService;
+
+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;
+
+class RetryTest {
+
+    @Test
+    void testRetryCreate() {
+        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = 
Mockito.mockStatic(NacosFactory.class)) {
+            AtomicInteger atomicInteger = new AtomicInteger(0);
+            ConfigService mock = new MockConfigService() {
+                @Override
+                public String getServerStatus() {
+                    return atomicInteger.incrementAndGet() > 10 ? UP : DOWN;
+                }
+            };
+            nacosFactoryMockedStatic.when(() -> 
NacosFactory.createConfigService((Properties) any())).thenReturn(mock);
+
+
+            URL url = URL.valueOf("nacos://127.0.0.1:8848")
+                .addParameter("nacos.retry", 5)
+                .addParameter("nacos.retry-wait", 10);
+            Assertions.assertThrows(IllegalStateException.class, () -> new 
NacosMetadataReport(url));
+
+            try {
+                new NacosMetadataReport(url);
+            } catch (Throwable t) {
+                Assertions.fail(t);
+            }
+        }
+    }
+    @Test
+    void testDisable() {
+        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = 
Mockito.mockStatic(NacosFactory.class)) {
+            ConfigService mock = new MockConfigService() {
+                @Override
+                public String getServerStatus() {
+                    return DOWN;
+                }
+            };
+            nacosFactoryMockedStatic.when(() -> 
NacosFactory.createConfigService((Properties) any())).thenReturn(mock);
+
+
+            URL url = URL.valueOf("nacos://127.0.0.1:8848")
+                .addParameter("nacos.retry", 5)
+                .addParameter("nacos.retry-wait", 10)
+                .addParameter("nacos.check", "false");
+            try {
+                new NacosMetadataReport(url);
+            } catch (Throwable t) {
+                Assertions.fail(t);
+            }
+        }
+    }
+}
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 e1185aa15b..6bc12e17b6 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
@@ -117,7 +117,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);
@@ -151,7 +151,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 c085701d86..b7809911a2 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
@@ -20,6 +20,7 @@ import java.util.Map;
 import java.util.Properties;
 
 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;
@@ -39,8 +40,10 @@ 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.api.common.Constants.DEFAULT_GROUP;
+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.CommonConstants.GROUP_KEY;
+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;
@@ -57,6 +60,8 @@ public class NacosNamingServiceUtils {
 
     private static final String NACOS_RETRY_KEY = "nacos.retry";
 
+    private static final String NACOS_CHECK_KEY = "nacos.check";
+
     private static final String NACOS_RETRY_WAIT_KEY = "nacos.retry-wait";
 
 
@@ -119,17 +124,39 @@ public class NacosNamingServiceUtils {
      */
     public static NacosNamingServiceWrapper createNamingService(URL 
connectionURL) {
         Properties nacosProperties = buildNacosProperties(connectionURL);
-        NamingService namingService;
+        int retryTimes = connectionURL.getPositiveParameter(NACOS_RETRY_KEY, 
10);
+        int sleepMsBetweenRetries = 
connectionURL.getPositiveParameter(NACOS_RETRY_WAIT_KEY, 1000);
+        boolean check = connectionURL.getParameter(NACOS_CHECK_KEY, true);
+        NamingService namingService = null;
         try {
-            namingService = NacosFactory.createNamingService(nacosProperties);
-        } catch (NacosException e) {
-            if (logger.isErrorEnabled()) {
-                logger.error(REGISTRY_NACOS_EXCEPTION, "", "", e.getErrMsg(), 
e);
+            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) {
+            logger.error(REGISTRY_NACOS_EXCEPTION, "", "", e.getErrMsg(), e);
+            throw new IllegalStateException(e);
+        } catch (InterruptedException e) {
+            logger.error(INTERNAL_INTERRUPTED, "", "", "Interrupted when 
creating nacos naming service client.", e);
+            Thread.currentThread().interrupt();
             throw new IllegalStateException(e);
         }
-        int retryTimes = connectionURL.getParameter(NACOS_RETRY_KEY, 10);
-        int sleepMsBetweenRetries = 
connectionURL.getParameter(NACOS_RETRY_WAIT_KEY, 10);
+
+        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 new NacosNamingServiceWrapper(namingService, retryTimes, 
sleepMsBetweenRetries);
     }
 
diff --git 
a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosRegistryFactoryTest.java
 
b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosRegistryFactoryTest.java
index 1df7d4d760..2af57626a4 100644
--- 
a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosRegistryFactoryTest.java
+++ 
b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosRegistryFactoryTest.java
@@ -18,7 +18,6 @@ package org.apache.dubbo.registry.nacos;
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.utils.NetUtils;
-
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
@@ -42,7 +41,7 @@ class NacosRegistryFactoryTest {
 
     @Test
     void testCreateRegistryCacheKey() {
-        URL url = URL.valueOf("dubbo://" + 
NetUtils.getLocalAddress().getHostAddress() + ":8080");
+        URL url = URL.valueOf("dubbo://" + 
NetUtils.getLocalAddress().getHostAddress() + ":8080?nacos.check=false");
         String registryCacheKey1 = 
nacosRegistryFactory.createRegistryCacheKey(url);
         String registryCacheKey2 = 
nacosRegistryFactory.createRegistryCacheKey(url);
         Assertions.assertEquals(registryCacheKey1, registryCacheKey2);
@@ -50,7 +49,7 @@ class NacosRegistryFactoryTest {
 
     @Test
     void testCreateRegistryCacheKeyWithNamespace() {
-        URL url = URL.valueOf("dubbo://" + 
NetUtils.getLocalAddress().getHostAddress() + ":8080?namespace=test");
+        URL url = URL.valueOf("dubbo://" + 
NetUtils.getLocalAddress().getHostAddress() + 
":8080?namespace=test&nacos.check=false");
         String registryCacheKey1 = 
nacosRegistryFactory.createRegistryCacheKey(url);
         String registryCacheKey2 = 
nacosRegistryFactory.createRegistryCacheKey(url);
         Assertions.assertEquals(registryCacheKey1, registryCacheKey2);
diff --git 
a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosRegistryTest.java
 
b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosRegistryTest.java
index c0568d3c52..82efa81bd9 100644
--- 
a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosRegistryTest.java
+++ 
b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosRegistryTest.java
@@ -69,7 +69,7 @@ class NacosRegistryTest {
 
         int nacosServerPort = NetUtils.getAvailablePort();
 
-        this.registryUrl = URL.valueOf("nacos://localhost:" + nacosServerPort);
+        this.registryUrl = URL.valueOf("nacos://localhost:" + nacosServerPort 
+ "?nacos.check=false");
 
         this.nacosRegistryFactory = new NacosRegistryFactory();
 
diff --git 
a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosServiceDiscoveryFactoryTest.java
 
b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosServiceDiscoveryFactoryTest.java
index c52466d9a6..6f9003490c 100644
--- 
a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosServiceDiscoveryFactoryTest.java
+++ 
b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosServiceDiscoveryFactoryTest.java
@@ -20,7 +20,6 @@ import org.apache.dubbo.common.URL;
 import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.registry.client.ServiceDiscovery;
 import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -42,7 +41,7 @@ class NacosServiceDiscoveryFactoryTest {
 
     @Test
     void testGetServiceDiscoveryWithCache() {
-        URL url = URL.valueOf("dubbo://test:8080");
+        URL url = URL.valueOf("dubbo://test:8080?nacos.check=false");
         ServiceDiscovery discovery = 
nacosServiceDiscoveryFactory.createDiscovery(url);
 
         Assertions.assertTrue(discovery instanceof NacosServiceDiscovery);
diff --git 
a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosServiceDiscoveryTest.java
 
b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosServiceDiscoveryTest.java
index 962acca8af..d994a08f59 100644
--- 
a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosServiceDiscoveryTest.java
+++ 
b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosServiceDiscoveryTest.java
@@ -16,6 +16,12 @@
  */
 package org.apache.dubbo.registry.nacos;
 
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.utils.NetUtils;
 import org.apache.dubbo.config.ApplicationConfig;
@@ -25,10 +31,6 @@ import 
org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;
 import 
org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.ScopeModelUtil;
-
-import com.alibaba.nacos.api.exception.NacosException;
-import com.alibaba.nacos.api.naming.pojo.Instance;
-import com.alibaba.nacos.api.naming.pojo.ListView;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeAll;
@@ -37,11 +39,9 @@ import org.junit.jupiter.api.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.internal.util.collections.Sets;
 
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
+import com.alibaba.nacos.api.exception.NacosException;
+import com.alibaba.nacos.api.naming.pojo.Instance;
+import com.alibaba.nacos.api.naming.pojo.ListView;
 
 import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -63,7 +63,7 @@ class NacosServiceDiscoveryTest {
 
     private static final String LOCALHOST = "127.0.0.1";
 
-    protected URL registryUrl = URL.valueOf("nacos://127.0.0.1:" + 
NetUtils.getAvailablePort());
+    protected URL registryUrl = URL.valueOf("nacos://127.0.0.1:" + 
NetUtils.getAvailablePort() + "?nacos.check=false");
 
     private NacosServiceDiscovery nacosServiceDiscovery;
 
@@ -79,7 +79,7 @@ class NacosServiceDiscoveryTest {
         public NacosServiceDiscoveryGroupTest1() {
             super();
             group = "test-group1";
-            registryUrl = URL.valueOf("nacos://127.0.0.1:" + 
NetUtils.getAvailablePort()).addParameter("group", group);
+            registryUrl = URL.valueOf("nacos://127.0.0.1:" + 
NetUtils.getAvailablePort() + "?nacos.check=false").addParameter("group", 
group);
         }
     }
 
@@ -87,7 +87,7 @@ class NacosServiceDiscoveryTest {
         public NacosServiceDiscoveryGroupTest2() {
             super();
             group = "test-group2";
-            registryUrl = URL.valueOf("nacos://127.0.0.1:" + 
NetUtils.getAvailablePort()).addParameter("group", group);
+            registryUrl = URL.valueOf("nacos://127.0.0.1:" + 
NetUtils.getAvailablePort() + "?nacos.check=false").addParameter("group", 
group);
         }
     }
 
@@ -97,7 +97,7 @@ class NacosServiceDiscoveryTest {
         public NacosServiceDiscoveryGroupTest3() {
             super();
             group = DEFAULT_GROUP;
-            registryUrl = URL.valueOf("nacos://127.0.0.1:" + 
NetUtils.getAvailablePort()).addParameter("group", "test-group3");
+            registryUrl = URL.valueOf("nacos://127.0.0.1:" + 
NetUtils.getAvailablePort() + "?nacos.check=false").addParameter("group", 
"test-group3");
         }
 
         @BeforeAll
diff --git 
a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/util/NacosNamingServiceUtilsTest.java
 
b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/util/NacosNamingServiceUtilsTest.java
index 701d97cffa..35c13d6a41 100644
--- 
a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/util/NacosNamingServiceUtilsTest.java
+++ 
b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/util/NacosNamingServiceUtilsTest.java
@@ -16,19 +16,29 @@
  */
 package org.apache.dubbo.registry.nacos.util;
 
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicInteger;
+
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.metadata.report.MetadataReport;
 import org.apache.dubbo.registry.client.ServiceInstance;
+import org.apache.dubbo.registry.nacos.MockNamingService;
 import org.apache.dubbo.registry.nacos.NacosNamingServiceWrapper;
-
-import com.alibaba.nacos.api.naming.pojo.Instance;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 
-import java.util.HashMap;
-import java.util.Map;
+import com.alibaba.nacos.api.NacosFactory;
+import com.alibaba.nacos.api.exception.NacosException;
+import com.alibaba.nacos.api.naming.NamingService;
+import com.alibaba.nacos.api.naming.pojo.Instance;
 
+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;
 import static org.mockito.Mockito.mock;
 
 /**
@@ -67,8 +77,35 @@ class NacosNamingServiceUtilsTest {
 
     @Test
     void testCreateNamingService() {
-        URL url = URL.valueOf("test://test:8080/test?backup=backup");
+        URL url = 
URL.valueOf("test://test:8080/test?backup=backup&nacos.check=false");
         NacosNamingServiceWrapper namingService = 
NacosNamingServiceUtils.createNamingService(url);
         Assertions.assertNotNull(namingService);
     }
+
+
+    @Test
+    void testRetryCreate() throws NacosException {
+        try (MockedStatic<NacosFactory> 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")
+                .addParameter("nacos.retry", 5)
+                .addParameter("nacos.retry-wait", 10);
+            Assertions.assertThrows(IllegalStateException.class, () -> 
NacosNamingServiceUtils.createNamingService(url));
+
+            try {
+                NacosNamingServiceUtils.createNamingService(url);
+            } catch (Throwable t) {
+                Assertions.fail(t);
+            }
+        }
+    }
 }


Reply via email to