Skip to content

Commit

Permalink
feat(#11393): support register or deregister persistent instance by g…
Browse files Browse the repository at this point in the history
…rpc in 2.3.0 server and client. (#11430)
  • Loading branch information
Bo-Qiu authored Nov 27, 2023
1 parent b50ccb0 commit 93cc842
Show file tree
Hide file tree
Showing 19 changed files with 573 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@

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;

/**
Expand All @@ -30,6 +30,12 @@
* @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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**.
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ public static String getGroupedNameOptional(final String serviceName, final Stri
* @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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
Original file line number Diff line number Diff line change
@@ -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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,19 @@ public void testCheckInstanceIsEphemeral() throws NacosException {
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() {
Expand Down
16 changes: 12 additions & 4 deletions api/src/test/java/com/alibaba/nacos/api/utils/AbilityKeyTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,20 @@ public void testMapStr() {

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
Expand All @@ -71,23 +75,27 @@ public void testMapEnum() {

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);
Expand All @@ -97,7 +105,7 @@ public void testGetAllValues() {
@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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ public void deregisterInstance(String serviceName, Instance instance) throws Nac

@Override
public void deregisterInstance(String serviceName, String groupName, Instance instance) throws NacosException {
NamingUtils.checkInstanceIsLegal(instance);
checkAndStripGroupNamePrefix(instance, groupName);
clientProxy.deregisterService(serviceName, groupName, instance);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -194,7 +195,10 @@ public boolean serverHealthy() {
}

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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -27,6 +29,7 @@
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;
Expand Down Expand Up @@ -129,6 +132,14 @@ public Class<? extends Event> subscribeType() {
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);
}
Expand Down Expand Up @@ -239,10 +250,32 @@ public void doRegisterService(String serviceName, String groupName, Instance ins
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) {
Expand Down Expand Up @@ -271,6 +304,20 @@ public void doDeregisterService(String serviceName, String groupName, Instance i
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 {
Expand Down Expand Up @@ -384,6 +431,16 @@ public boolean serverHealthy() {
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;
Expand Down
Loading

0 comments on commit 93cc842

Please sign in to comment.