Fix nacos create client retry conflicts

This commit is contained in:
Albumen Kevin 2023-01-14 21:50:23 +08:00
parent b38e23b5ce
commit c519eb47a3
5 changed files with 120 additions and 27 deletions

View File

@ -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<NamingService> 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;
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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<NamingService> 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<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");
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<NacosFactory> 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);
}
}
}
}

View File

@ -91,7 +91,7 @@ class NacosNamingServiceWrapperTest {
@Test
void testRegisterNacos2_0_x() throws NacosException {
List<NamingService> 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<NamingService> 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<NamingService> 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<NamingService> 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);