feat(#11393): support register or deregister persistent instance by grpc in 2.3.0 server and client. (#11430)

This commit is contained in:
blake.qiu 2023-11-27 19:47:20 +08:00 committed by GitHub
parent b50ccb0b15
commit 93cc842c90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 573 additions and 15 deletions

View File

@ -18,8 +18,8 @@ package com.alibaba.nacos.api.ability.constant;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
/**
@ -30,6 +30,12 @@ import java.util.stream.Collectors;
* @date 2022/8/31 12:27
**/
public enum AbilityKey {
/**
* Server support register or deregister persistent instance by grpc.
*/
SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC("supportPersistentInstanceByGrpc",
"support persistent instance by grpc", AbilityMode.SERVER),
/**
* For Test temporarily.

View File

@ -45,6 +45,7 @@ public class ServerAbilities extends AbstractAbilityRegistry {
*
*/
// put ability here, which you want current server supports
supportedAbilities.put(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC, true);
}
/**.

View File

@ -0,0 +1,56 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.api.naming.remote.request;
import com.alibaba.nacos.api.naming.pojo.Instance;
/**
* Nacos persistent instances request.
*
* @author blake.qiu
*/
public class PersistentInstanceRequest extends AbstractNamingRequest {
private String type;
private Instance instance;
public PersistentInstanceRequest() {
}
public PersistentInstanceRequest(String namespace, String serviceName, String groupName, String type, Instance instance) {
super(namespace, serviceName, groupName);
this.type = type;
this.instance = instance;
}
public String getType() {
return this.type;
}
public void setType(String type) {
this.type = type;
}
public Instance getInstance() {
return instance;
}
public void setInstance(Instance instance) {
this.instance = instance;
}
}

View File

@ -138,6 +138,10 @@ public class NamingUtils {
* @throws NacosException if check failed, throw exception
*/
public static void checkInstanceIsLegal(Instance instance) throws NacosException {
if (null == instance) {
throw new NacosApiException(NacosException.INVALID_PARAM, ErrorCode.INSTANCE_ERROR,
"Instance can not be null.");
}
if (instance.getInstanceHeartBeatTimeOut() < instance.getInstanceHeartBeatInterval()
|| instance.getIpDeleteTimeout() < instance.getInstanceHeartBeatInterval()) {
throw new NacosApiException(NacosException.INVALID_PARAM, ErrorCode.INSTANCE_ERROR,

View File

@ -47,6 +47,7 @@ com.alibaba.nacos.api.config.remote.request.cluster.ConfigChangeClusterSyncReque
com.alibaba.nacos.api.config.remote.response.cluster.ConfigChangeClusterSyncResponse
com.alibaba.nacos.api.naming.remote.request.BatchInstanceRequest
com.alibaba.nacos.api.naming.remote.request.InstanceRequest
com.alibaba.nacos.api.naming.remote.request.PersistentInstanceRequest
com.alibaba.nacos.api.naming.remote.request.NotifySubscriberRequest
com.alibaba.nacos.api.naming.remote.request.ServiceListRequest
com.alibaba.nacos.api.naming.remote.request.ServiceQueryRequest

View File

@ -16,15 +16,21 @@
package com.alibaba.nacos.api.ability.register.impl;
import com.alibaba.nacos.api.ability.constant.AbilityKey;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class ServerAbilitiesTest {
@Test
public void testGetStaticAbilities() {
// TODO add the server abilities.
assertTrue(ServerAbilities.getStaticAbilities().isEmpty());
assertFalse(ServerAbilities.getStaticAbilities().isEmpty());
}
@Test
public void testSupportPersistentInstanceByGrpcAbilities() {
assertTrue(ServerAbilities.getStaticAbilities().get(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC));
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 1999-2021 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.api.naming.remote.request;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.remote.NamingRemoteConstants;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class PersistentInstanceRequestTest extends BasedNamingRequestTest {
@Test
public void testSerialize() throws JsonProcessingException {
PersistentInstanceRequest request = new PersistentInstanceRequest(NAMESPACE, SERVICE, GROUP,
NamingRemoteConstants.REGISTER_INSTANCE, new Instance());
String json = mapper.writeValueAsString(request);
checkSerializeBasedInfo(json);
assertTrue(json.contains("\"type\":\"" + NamingRemoteConstants.REGISTER_INSTANCE + "\""));
assertTrue(json.contains("\"instance\":{"));
}
@Test
public void testDeserialize() throws JsonProcessingException {
String json = "{\"headers\":{},\"namespace\":\"namespace\",\"serviceName\":\"service\",\"groupName\":\"group\","
+ "\"type\":\"deregisterInstance\",\"instance\":{\"port\":0,\"weight\":1.0,\"healthy\":true,"
+ "\"enabled\":true,\"ephemeral\":true,\"metadata\":{},\"instanceIdGenerator\":\"simple\","
+ "\"instanceHeartBeatInterval\":5000,\"instanceHeartBeatTimeOut\":15000,\"ipDeleteTimeout\":30000},"
+ "\"module\":\"naming\"}";
PersistentInstanceRequest actual = mapper.readValue(json, PersistentInstanceRequest.class);
checkNamingRequestBasedInfo(actual);
assertEquals(NamingRemoteConstants.DE_REGISTER_INSTANCE, actual.getType());
assertEquals(new Instance(), actual.getInstance());
}
}

View File

@ -231,6 +231,19 @@ public class NamingUtilsTest {
Assert.assertEquals(e.getErrCode(), NacosException.INVALID_PARAM);
}
}
@Test
public void testCheckInstanceIsNull() throws NacosException {
Instance instance = new Instance();
instance.setIp("127.0.0.1");
instance.setPort(9089);
NamingUtils.checkInstanceIsLegal(instance);
try {
NamingUtils.checkInstanceIsLegal(null);
} catch (NacosException e) {
Assert.assertEquals(e.getErrCode(), NacosException.INVALID_PARAM);
}
}
@Test
public void testIsNumber() {

View File

@ -44,16 +44,20 @@ public class AbilityKeyTest {
enumMap.put(AbilityKey.SERVER_TEST_1, true);
enumMap.put(AbilityKey.SERVER_TEST_2, false);
enumMap.put(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC, false);
stringBooleanMap = AbilityKey.mapStr(enumMap);
assertEquals(2, stringBooleanMap.size());
assertEquals(3, stringBooleanMap.size());
Assert.assertTrue(stringBooleanMap.get(AbilityKey.SERVER_TEST_1.getName()));
Assert.assertFalse(stringBooleanMap.get(AbilityKey.SERVER_TEST_2.getName()));
Assert.assertFalse(stringBooleanMap.get(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC.getName()));
enumMap.put(AbilityKey.SERVER_TEST_2, true);
enumMap.put(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC, true);
stringBooleanMap = AbilityKey.mapStr(enumMap);
assertEquals(2, stringBooleanMap.size());
assertEquals(3, stringBooleanMap.size());
Assert.assertTrue(stringBooleanMap.get(AbilityKey.SERVER_TEST_1.getName()));
Assert.assertTrue(stringBooleanMap.get(AbilityKey.SERVER_TEST_2.getName()));
Assert.assertTrue(stringBooleanMap.get(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC.getName()));
}
@Test
@ -71,23 +75,27 @@ public class AbilityKeyTest {
mapStr.put(AbilityKey.SERVER_TEST_2.getName(), false);
mapStr.put(AbilityKey.SERVER_TEST_1.getName(), true);
mapStr.put(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC.getName(), true);
enumMap = AbilityKey.mapEnum(AbilityMode.SERVER, mapStr);
Assert.assertFalse(enumMap.get(AbilityKey.SERVER_TEST_2));
Assert.assertTrue(enumMap.get(AbilityKey.SERVER_TEST_1));
Assert.assertTrue(enumMap.get(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC));
mapStr.clear();
mapStr.put(AbilityKey.SERVER_TEST_2.getName(), true);
mapStr.put(AbilityKey.SERVER_TEST_1.getName(), true);
mapStr.put(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC.getName(), true);
enumMap = AbilityKey.mapEnum(AbilityMode.SERVER, mapStr);
Assert.assertTrue(enumMap.get(AbilityKey.SERVER_TEST_2));
Assert.assertTrue(enumMap.get(AbilityKey.SERVER_TEST_1));
Assert.assertTrue(enumMap.get(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC));
}
@Test
public void testGetAllValues() {
Collection<AbilityKey> actual = AbilityKey.getAllValues(AbilityMode.SERVER);
assertEquals(2, actual.size());
assertEquals(3, actual.size());
actual = AbilityKey.getAllValues(AbilityMode.SDK_CLIENT);
assertEquals(1, actual.size());
actual = AbilityKey.getAllValues(AbilityMode.CLUSTER_CLIENT);
@ -97,7 +105,7 @@ public class AbilityKeyTest {
@Test
public void testGetAllNames() {
Collection<String> actual = AbilityKey.getAllNames(AbilityMode.SERVER);
assertEquals(2, actual.size());
assertEquals(3, actual.size());
actual = AbilityKey.getAllNames(AbilityMode.SDK_CLIENT);
assertEquals(1, actual.size());
actual = AbilityKey.getAllNames(AbilityMode.CLUSTER_CLIENT);

View File

@ -194,6 +194,7 @@ public class NacosNamingService implements NamingService {
@Override
public void deregisterInstance(String serviceName, String groupName, Instance instance) throws NacosException {
NamingUtils.checkInstanceIsLegal(instance);
checkAndStripGroupNamePrefix(instance, groupName);
clientProxy.deregisterService(serviceName, groupName, instance);
}

View File

@ -16,6 +16,7 @@
package com.alibaba.nacos.client.naming.remote;
import com.alibaba.nacos.api.ability.constant.AbilityKey;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
@ -194,7 +195,10 @@ public class NamingClientProxyDelegate implements NamingClientProxy {
}
private NamingClientProxy getExecuteClientProxy(Instance instance) {
return instance.isEphemeral() ? grpcClientProxy : httpClientProxy;
if (instance.isEphemeral() || grpcClientProxy.isAbilitySupportedByServer(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC)) {
return grpcClientProxy;
}
return httpClientProxy;
}
@Override

View File

@ -16,6 +16,8 @@
package com.alibaba.nacos.client.naming.remote.gprc;
import com.alibaba.nacos.api.ability.constant.AbilityKey;
import com.alibaba.nacos.api.ability.constant.AbilityStatus;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.CommonParams;
@ -27,6 +29,7 @@ import com.alibaba.nacos.api.naming.remote.NamingRemoteConstants;
import com.alibaba.nacos.api.naming.remote.request.AbstractNamingRequest;
import com.alibaba.nacos.api.naming.remote.request.BatchInstanceRequest;
import com.alibaba.nacos.api.naming.remote.request.InstanceRequest;
import com.alibaba.nacos.api.naming.remote.request.PersistentInstanceRequest;
import com.alibaba.nacos.api.naming.remote.request.ServiceListRequest;
import com.alibaba.nacos.api.naming.remote.request.ServiceQueryRequest;
import com.alibaba.nacos.api.naming.remote.request.SubscribeServiceRequest;
@ -129,6 +132,14 @@ public class NamingGrpcClientProxy extends AbstractNamingClientProxy {
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance {}", namespaceId, serviceName,
instance);
if (instance.isEphemeral()) {
registerServiceForEphemeral(serviceName, groupName, instance);
} else {
doRegisterServiceForPersistent(serviceName, groupName, instance);
}
}
private void registerServiceForEphemeral(String serviceName, String groupName, Instance instance) throws NacosException {
redoService.cacheInstanceForRedo(serviceName, groupName, instance);
doRegisterService(serviceName, groupName, instance);
}
@ -239,10 +250,32 @@ public class NamingGrpcClientProxy extends AbstractNamingClientProxy {
redoService.instanceRegistered(serviceName, groupName);
}
/**
* Execute register operation for persistent instance.
*
* @param serviceName name of service
* @param groupName group of service
* @param instance instance to register
* @throws NacosException nacos exception
*/
public void doRegisterServiceForPersistent(String serviceName, String groupName, Instance instance) throws NacosException {
PersistentInstanceRequest request = new PersistentInstanceRequest(namespaceId, serviceName, groupName,
NamingRemoteConstants.REGISTER_INSTANCE, instance);
requestToServer(request, Response.class);
}
@Override
public void deregisterService(String serviceName, String groupName, Instance instance) throws NacosException {
NAMING_LOGGER.info("[DEREGISTER-SERVICE] {} deregistering service {} with instance: {}", namespaceId,
serviceName, instance);
if (instance.isEphemeral()) {
deregisterServiceForEphemeral(serviceName, groupName, instance);
} else {
doDeregisterServiceForPersistent(serviceName, groupName, instance);
}
}
private void deregisterServiceForEphemeral(String serviceName, String groupName, Instance instance) throws NacosException {
String key = NamingUtils.getGroupedName(serviceName, groupName);
InstanceRedoData instanceRedoData = redoService.getRegisteredInstancesByKey(key);
if (instanceRedoData instanceof BatchInstanceRedoData) {
@ -271,6 +304,20 @@ public class NamingGrpcClientProxy extends AbstractNamingClientProxy {
requestToServer(request, Response.class);
redoService.instanceDeregistered(serviceName, groupName);
}
/**
* Execute deregister operation for persistent instance.
*
* @param serviceName service name
* @param groupName group name
* @param instance instance
* @throws NacosException nacos exception
*/
public void doDeregisterServiceForPersistent(String serviceName, String groupName, Instance instance) throws NacosException {
PersistentInstanceRequest request = new PersistentInstanceRequest(namespaceId, serviceName, groupName,
NamingRemoteConstants.DE_REGISTER_INSTANCE, instance);
requestToServer(request, Response.class);
}
@Override
public void updateInstance(String serviceName, String groupName, Instance instance) throws NacosException {
@ -384,6 +431,16 @@ public class NamingGrpcClientProxy extends AbstractNamingClientProxy {
return rpcClient.isRunning();
}
/**
* Determine whether nacos-server supports the capability.
*
* @param abilityKey ability key
* @return true if supported, otherwise false
*/
public boolean isAbilitySupportedByServer(AbilityKey abilityKey) {
return rpcClient.getConnectionAbility(abilityKey) == AbilityStatus.SUPPORTED;
}
private <T extends Response> T requestToServer(AbstractNamingRequest request, Class<T> responseClass)
throws NacosException {
Response response = null;

View File

@ -268,7 +268,6 @@ public class NamingHttpClientProxy extends AbstractNamingClientProxy {
@Override
public boolean serverHealthy() {
try {
String result = reqApi(UtilAndComs.nacosUrlBase + "/operator/metrics", new HashMap<>(8), HttpMethod.GET);
JsonNode json = JacksonUtils.toObj(result);

View File

@ -18,6 +18,7 @@
package com.alibaba.nacos.client.naming.remote;
import com.alibaba.nacos.api.ability.constant.AbilityKey;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.Service;
@ -46,7 +47,7 @@ import static org.mockito.Mockito.when;
public class NamingClientProxyDelegateTest {
@Test
public void testRegisterServiceByGrpc() throws NacosException, NoSuchFieldException, IllegalAccessException {
public void testRegisterEphemeralServiceByGrpc() throws NacosException, NoSuchFieldException, IllegalAccessException {
String ns = "ns1";
ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class);
Properties props = new Properties();
@ -100,7 +101,36 @@ public class NamingClientProxyDelegateTest {
}
@Test
public void testRegisterServiceByHttp() throws NacosException, NoSuchFieldException, IllegalAccessException {
public void testRegisterPersistentServiceByGrpc() throws NacosException, NoSuchFieldException, IllegalAccessException {
String ns = "ns1";
ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class);
Properties props = new Properties();
props.setProperty("serverAddr", "localhost");
final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props);
InstancesChangeNotifier notifier = new InstancesChangeNotifier();
NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, nacosClientProperties, notifier);
NamingGrpcClientProxy mockGrpcClient = Mockito.mock(NamingGrpcClientProxy.class);
Field grpcClientProxyField = NamingClientProxyDelegate.class.getDeclaredField("grpcClientProxy");
grpcClientProxyField.setAccessible(true);
grpcClientProxyField.set(delegate, mockGrpcClient);
String serviceName = "service1";
String groupName = "group1";
Instance instance = new Instance();
instance.setServiceName(serviceName);
instance.setClusterName(groupName);
instance.setIp("1.1.1.1");
instance.setPort(1);
// persistent instance
instance.setEphemeral(false);
// when server support register persistent instance by grpc, will use grpc to register
when(mockGrpcClient.isAbilitySupportedByServer(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC)).thenReturn(true);
delegate.registerService(serviceName, groupName, instance);
verify(mockGrpcClient, times(1)).registerService(serviceName, groupName, instance);
}
@Test
public void testRegisterPersistentServiceByHttp() throws NacosException, NoSuchFieldException, IllegalAccessException {
String ns = "ns1";
ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class);
Properties props = new Properties();
@ -121,14 +151,15 @@ public class NamingClientProxyDelegateTest {
instance.setClusterName(groupName);
instance.setIp("1.1.1.1");
instance.setPort(1);
// use grpc
// persistent instance
instance.setEphemeral(false);
// when server do not support register persistent instance by grpc, will use http to register
delegate.registerService(serviceName, groupName, instance);
verify(mockHttpClient, times(1)).registerService(serviceName, groupName, instance);
}
@Test
public void testDeregisterServiceGrpc() throws NacosException, NoSuchFieldException, IllegalAccessException {
public void testDeregisterEphemeralServiceGrpc() throws NacosException, NoSuchFieldException, IllegalAccessException {
String ns = "ns1";
ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class);
Properties props = new Properties();
@ -156,13 +187,43 @@ public class NamingClientProxyDelegateTest {
}
@Test
public void testDeregisterServiceHttp() throws NacosException, NoSuchFieldException, IllegalAccessException {
public void testDeregisterPersistentServiceGrpc() throws NacosException, NoSuchFieldException, IllegalAccessException {
String ns = "ns1";
ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class);
Properties props = new Properties();
props.setProperty("serverAddr", "localhost");
InstancesChangeNotifier notifier = new InstancesChangeNotifier();
final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props);
NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, nacosClientProperties, notifier);
NamingGrpcClientProxy mockGrpcClient = Mockito.mock(NamingGrpcClientProxy.class);
Field grpcClientProxyField = NamingClientProxyDelegate.class.getDeclaredField("grpcClientProxy");
grpcClientProxyField.setAccessible(true);
grpcClientProxyField.set(delegate, mockGrpcClient);
String serviceName = "service1";
String groupName = "group1";
Instance instance = new Instance();
instance.setServiceName(serviceName);
instance.setClusterName(groupName);
instance.setIp("1.1.1.1");
instance.setPort(1);
// persistent instance
instance.setEphemeral(false);
// when server support deregister persistent instance by grpc, will use grpc to deregister
when(mockGrpcClient.isAbilitySupportedByServer(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC)).thenReturn(true);
delegate.deregisterService(serviceName, groupName, instance);
verify(mockGrpcClient, times(1)).deregisterService(serviceName, groupName, instance);
}
@Test
public void testDeregisterPersistentServiceHttp() throws NacosException, NoSuchFieldException, IllegalAccessException {
String ns = "ns1";
ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class);
Properties props = new Properties();
props.setProperty("serverAddr", "localhost");
InstancesChangeNotifier notifier = new InstancesChangeNotifier();
final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props);
NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, nacosClientProperties, notifier);
NamingHttpClientProxy mockHttpClient = Mockito.mock(NamingHttpClientProxy.class);

View File

@ -18,6 +18,8 @@
package com.alibaba.nacos.client.naming.remote.gprc;
import com.alibaba.nacos.api.ability.constant.AbilityKey;
import com.alibaba.nacos.api.ability.constant.AbilityStatus;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
@ -27,6 +29,7 @@ import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.api.naming.remote.NamingRemoteConstants;
import com.alibaba.nacos.api.naming.remote.request.BatchInstanceRequest;
import com.alibaba.nacos.api.naming.remote.request.InstanceRequest;
import com.alibaba.nacos.api.naming.remote.request.PersistentInstanceRequest;
import com.alibaba.nacos.api.naming.remote.request.SubscribeServiceRequest;
import com.alibaba.nacos.api.naming.remote.response.BatchInstanceResponse;
import com.alibaba.nacos.api.naming.remote.response.InstanceResponse;
@ -123,6 +126,8 @@ public class NamingGrpcClientProxyTest {
private Instance instance;
private Instance persistentInstance;
private String uuid;
@Rule
@ -143,7 +148,7 @@ public class NamingGrpcClientProxyTest {
Field uuidField = NamingGrpcClientProxy.class.getDeclaredField("uuid");
uuidField.setAccessible(true);
uuid = (String) uuidField.get(client);
Assert.assertNotNull(RpcClientFactory.getClient(uuid));
Field rpcClientField = NamingGrpcClientProxy.class.getDeclaredField("rpcClient");
rpcClientField.setAccessible(true);
@ -156,6 +161,12 @@ public class NamingGrpcClientProxyTest {
instance.setServiceName(SERVICE_NAME);
instance.setIp("1.1.1.1");
instance.setPort(1111);
persistentInstance = new Instance();
persistentInstance.setServiceName(SERVICE_NAME);
persistentInstance.setIp("1.1.1.1");
persistentInstance.setPort(1111);
persistentInstance.setEphemeral(false);
}
@After
@ -177,6 +188,18 @@ public class NamingGrpcClientProxyTest {
}));
}
@Test
public void testRegisterPersistentService() throws NacosException {
client.registerService(SERVICE_NAME, GROUP_NAME, persistentInstance);
verify(this.rpcClient, times(1)).request(argThat(request -> {
if (request instanceof PersistentInstanceRequest) {
PersistentInstanceRequest request1 = (PersistentInstanceRequest) request;
return request1.getType().equals(NamingRemoteConstants.REGISTER_INSTANCE);
}
return false;
}));
}
@Test
public void testRegisterServiceThrowsNacosException() throws NacosException {
expectedException.expect(NacosException.class);
@ -220,6 +243,18 @@ public class NamingGrpcClientProxyTest {
return false;
}));
}
@Test
public void testDeregisterPersistentService() throws NacosException {
client.deregisterService(SERVICE_NAME, GROUP_NAME, persistentInstance);
verify(this.rpcClient, times(1)).request(argThat(request -> {
if (request instanceof PersistentInstanceRequest) {
PersistentInstanceRequest request1 = (PersistentInstanceRequest) request;
return request1.getType().equals(NamingRemoteConstants.DE_REGISTER_INSTANCE);
}
return false;
}));
}
@Test
public void testDeregisterServiceForBatchRegistered() throws NacosException {
@ -461,6 +496,42 @@ public class NamingGrpcClientProxyTest {
Assert.assertTrue(client.serverHealthy());
verify(this.rpcClient, times(1)).isRunning();
}
@Test
public void testIsAbilitySupportedByServer1() {
when(this.rpcClient.getConnectionAbility(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC))
.thenReturn(AbilityStatus.SUPPORTED);
Assert.assertTrue(client.isAbilitySupportedByServer(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC));
verify(this.rpcClient, times(1))
.getConnectionAbility(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC);
}
@Test
public void testIsAbilitySupportedByServer2() {
when(this.rpcClient.getConnectionAbility(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC))
.thenReturn(AbilityStatus.NOT_SUPPORTED);
Assert.assertFalse(client.isAbilitySupportedByServer(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC));
verify(this.rpcClient, times(1))
.getConnectionAbility(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC);
}
@Test
public void testIsAbilitySupportedByServer3() {
when(this.rpcClient.getConnectionAbility(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC))
.thenReturn(AbilityStatus.UNKNOWN);
Assert.assertFalse(client.isAbilitySupportedByServer(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC));
verify(this.rpcClient, times(1))
.getConnectionAbility(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC);
}
@Test
public void testIsAbilitySupportedByServer4() {
when(this.rpcClient.getConnectionAbility(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC))
.thenReturn(null);
Assert.assertFalse(client.isAbilitySupportedByServer(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC));
verify(this.rpcClient, times(1))
.getConnectionAbility(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC);
}
@Test
public void testShutdown() throws Exception {

View File

@ -0,0 +1,55 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.core.paramcheck.impl;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.remote.request.PersistentInstanceRequest;
import com.alibaba.nacos.api.remote.request.Request;
import com.alibaba.nacos.common.paramcheck.ParamInfo;
import com.alibaba.nacos.core.paramcheck.AbstractRpcParamExtractor;
import java.util.ArrayList;
import java.util.List;
/**
* Param extractor for {@link com.alibaba.nacos.api.naming.remote.request.PersistentInstanceRequest}.
*
* @author blake.qiu
*/
public class PersistentInstanceRequestParamExtractor extends AbstractRpcParamExtractor {
@Override
public List<ParamInfo> extractParam(Request request) {
PersistentInstanceRequest req = (PersistentInstanceRequest) request;
ParamInfo paramInfo = new ParamInfo();
paramInfo.setNamespaceId(req.getNamespace());
paramInfo.setServiceName(req.getServiceName());
paramInfo.setGroup(req.getGroupName());
Instance instance = req.getInstance();
ArrayList<ParamInfo> paramInfos = new ArrayList<>();
if (instance == null) {
paramInfos.add(paramInfo);
return paramInfos;
}
paramInfo.setIp(instance.getIp());
paramInfo.setPort(String.valueOf(instance.getPort()));
paramInfo.setCluster(instance.getClusterName());
paramInfo.setMetadata(instance.getMetadata());
paramInfos.add(paramInfo);
return paramInfos;
}
}

View File

@ -18,6 +18,7 @@ com.alibaba.nacos.core.paramcheck.impl.SubscribeServiceRequestParamExtractor
com.alibaba.nacos.core.paramcheck.impl.ServiceQueryRequestParamExtractor
com.alibaba.nacos.core.paramcheck.impl.ServiceListRequestParamExtractor
com.alibaba.nacos.core.paramcheck.impl.InstanceRequestParamExtractor
com.alibaba.nacos.core.paramcheck.impl.PersistentInstanceRequestParamExtractor
com.alibaba.nacos.core.paramcheck.impl.ConfigRequestParamExtractor
com.alibaba.nacos.core.paramcheck.impl.ConfigBatchListenRequestParamExtractor
com.alibaba.nacos.core.paramcheck.impl.BatchInstanceRequestParamExtractor

View File

@ -0,0 +1,92 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.naming.remote.rpc.handler;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.remote.NamingRemoteConstants;
import com.alibaba.nacos.api.naming.remote.request.PersistentInstanceRequest;
import com.alibaba.nacos.api.naming.remote.response.InstanceResponse;
import com.alibaba.nacos.api.remote.request.RequestMeta;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.trace.DeregisterInstanceReason;
import com.alibaba.nacos.common.trace.event.naming.DeregisterInstanceTraceEvent;
import com.alibaba.nacos.common.trace.event.naming.RegisterInstanceTraceEvent;
import com.alibaba.nacos.core.control.TpsControl;
import com.alibaba.nacos.core.paramcheck.ExtractorManager;
import com.alibaba.nacos.core.paramcheck.impl.PersistentInstanceRequestParamExtractor;
import com.alibaba.nacos.core.remote.RequestHandler;
import com.alibaba.nacos.naming.core.v2.client.impl.IpPortBasedClient;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import com.alibaba.nacos.naming.core.v2.service.impl.PersistentClientOperationServiceImpl;
import com.alibaba.nacos.naming.utils.InstanceUtil;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import org.springframework.stereotype.Component;
/**
* Persistent instance request handler.
*
* @author blake.qiu
*/
@Component
public class PersistentInstanceRequestHandler extends RequestHandler<PersistentInstanceRequest, InstanceResponse> {
private final PersistentClientOperationServiceImpl clientOperationService;
public PersistentInstanceRequestHandler(PersistentClientOperationServiceImpl clientOperationService) {
this.clientOperationService = clientOperationService;
}
@Override
@TpsControl(pointName = "RemoteNamingInstanceRegisterDeregister", name = "RemoteNamingInstanceRegisterDeregister")
@Secured(action = ActionTypes.WRITE)
@ExtractorManager.Extractor(rpcExtractor = PersistentInstanceRequestParamExtractor.class)
public InstanceResponse handle(PersistentInstanceRequest request, RequestMeta meta) throws NacosException {
Service service = Service.newService(request.getNamespace(), request.getGroupName(), request.getServiceName(),
false);
InstanceUtil.setInstanceIdIfEmpty(request.getInstance(), service.getGroupedServiceName());
switch (request.getType()) {
case NamingRemoteConstants.REGISTER_INSTANCE:
return registerInstance(service, request, meta);
case NamingRemoteConstants.DE_REGISTER_INSTANCE:
return deregisterInstance(service, request, meta);
default:
throw new NacosException(NacosException.INVALID_PARAM,
String.format("Unsupported request type %s", request.getType()));
}
}
private InstanceResponse registerInstance(Service service, PersistentInstanceRequest request, RequestMeta meta) {
Instance instance = request.getInstance();
String clientId = IpPortBasedClient.getClientId(instance.toInetAddr(), false);
clientOperationService.registerInstance(service, instance, clientId);
NotifyCenter.publishEvent(new RegisterInstanceTraceEvent(System.currentTimeMillis(), meta.getClientIp(), true,
service.getNamespace(), service.getGroup(), service.getName(), instance.getIp(), instance.getPort()));
return new InstanceResponse(NamingRemoteConstants.REGISTER_INSTANCE);
}
private InstanceResponse deregisterInstance(Service service, PersistentInstanceRequest request, RequestMeta meta) {
Instance instance = request.getInstance();
String clientId = IpPortBasedClient.getClientId(instance.toInetAddr(), false);
clientOperationService.deregisterInstance(service, instance, clientId);
NotifyCenter.publishEvent(new DeregisterInstanceTraceEvent(System.currentTimeMillis(), meta.getClientIp(), true,
DeregisterInstanceReason.REQUEST, service.getNamespace(), service.getGroup(), service.getName(),
instance.getIp(), instance.getPort()));
return new InstanceResponse(NamingRemoteConstants.DE_REGISTER_INSTANCE);
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright 1999-2021 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.naming.remote.rpc.handler;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.remote.NamingRemoteConstants;
import com.alibaba.nacos.api.naming.remote.request.PersistentInstanceRequest;
import com.alibaba.nacos.api.remote.request.RequestMeta;
import com.alibaba.nacos.naming.core.v2.service.impl.PersistentClientOperationServiceImpl;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
/**
* {@link PersistentInstanceRequestHandler} unit tests.
*
* @author blake.qiu
*/
@RunWith(MockitoJUnitRunner.class)
public class PersistentInstanceRequestHandlerTest {
@InjectMocks
private PersistentInstanceRequestHandler persistentInstanceRequestHandler;
@Mock
private PersistentClientOperationServiceImpl clientOperationService;
@Test
public void testHandle() throws NacosException {
PersistentInstanceRequest instanceRequest = new PersistentInstanceRequest();
instanceRequest.setType(NamingRemoteConstants.REGISTER_INSTANCE);
instanceRequest.setServiceName("service1");
instanceRequest.setGroupName("group1");
Instance instance = new Instance();
instanceRequest.setInstance(instance);
RequestMeta requestMeta = new RequestMeta();
persistentInstanceRequestHandler.handle(instanceRequest, requestMeta);
Mockito.verify(clientOperationService).registerInstance(Mockito.any(), Mockito.any(), Mockito.anyString());
instanceRequest.setType(NamingRemoteConstants.DE_REGISTER_INSTANCE);
persistentInstanceRequestHandler.handle(instanceRequest, requestMeta);
Mockito.verify(clientOperationService).deregisterInstance(Mockito.any(), Mockito.any(), Mockito.anyString());
instanceRequest.setType("xxx");
try {
persistentInstanceRequestHandler.handle(instanceRequest, requestMeta);
} catch (Exception e) {
Assert.assertEquals(((NacosException) e).getErrCode(), NacosException.INVALID_PARAM);
}
}
}