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

liubao pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git

commit 1eb13a139d49ac30508585664b24c656d380b569
Author: liubao <bao....@huawei.com>
AuthorDate: Tue May 15 21:07:58 2018 +0800

    [SCB-582]Provide a way to protect instance removal
---
 .../src/main/resources/microservice.yaml           |  8 +++-
 .../api/registry/MicroserviceInstance.java         | 13 ++++++
 .../config/ServiceRegistryConfig.java              |  8 ++++
 .../consumer/MicroserviceInstancePing.java         | 34 ++++++++++++++++
 .../consumer/MicroserviceVersions.java             | 32 ++++++++++++---
 .../consumer/SimpleMicroserviceInstancePing.java   | 47 ++++++++++++++++++++++
 ...rviceregistry.consumer.MicroserviceInstancePing | 18 +++++++++
 .../api/registry/TestMicroServiceInstance.java     | 10 +++++
 .../client/LocalServiceRegistryClientImplTest.java |  1 +
 .../consumer/TestMicroserviceVersions.java         | 13 ++++++
 .../TestSimpleMicroserviceInstancePing.java        | 46 +++++++++++++++++++++
 .../transport/TestRestServletInitializer.java      |  2 +-
 12 files changed, 224 insertions(+), 8 deletions(-)

diff --git a/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml 
b/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml
index 7be293d..74d9481 100644
--- a/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml
+++ b/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml
@@ -23,6 +23,12 @@ servicecomb:
   service:
     registry:
       address: http://127.0.0.1:30100
+      instance:
+        healthCheck:
+          interval: 2
+        watch: false
+        remove:
+          protection: true
   handler:
     chain:
       Consumer:
@@ -32,4 +38,4 @@ servicecomb:
       enabled: false
   loadbalance:
     strategy:
-      name: Random
+      name: Random
\ No newline at end of file
diff --git 
a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceInstance.java
 
b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceInstance.java
index 293ab48..184aac3 100644
--- 
a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceInstance.java
+++ 
b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceInstance.java
@@ -139,6 +139,19 @@ public class MicroserviceInstance {
     return dataCenterInfo;
   }
 
+  @Override
+  public int hashCode() {
+    return this.instanceId.hashCode();
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof MicroserviceInstance) {
+      return this.instanceId.equals(((MicroserviceInstance) obj).instanceId);
+    }
+    return false;
+  }
+
   public void setDataCenterInfo(DataCenterInfo dataCenterInfo) {
     this.dataCenterInfo = dataCenterInfo;
   }
diff --git 
a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
 
b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
index e91444f..0d48a8b 100644
--- 
a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
+++ 
b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
@@ -224,6 +224,14 @@ public final class ServiceRegistryConfig {
     return times < 0 ? DEFAULT_CHECK_TIMES : times;
   }
 
+  public boolean isInstanceRemoveProtectionEnabled() {
+    DynamicBooleanProperty property =
+        DynamicPropertyFactory.getInstance()
+            
.getBooleanProperty("servicecomb.service.registry.instance.remove.protection",
+                false);
+    return property.get();
+  }
+
   public boolean isPreferIpAddress() {
     DynamicBooleanProperty property =
         DynamicPropertyFactory.getInstance()
diff --git 
a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceInstancePing.java
 
b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceInstancePing.java
new file mode 100644
index 0000000..7bbfa8c
--- /dev/null
+++ 
b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceInstancePing.java
@@ -0,0 +1,34 @@
+/*
+ * 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.servicecomb.serviceregistry.consumer;
+
+import 
org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+
+/**
+ * SPI interface to ping microservice instance status in Instance Protection 
Mode, which means
+ * protection of instance removal and usually used in scenarios where 
instances are fixed and changed rarely.
+ */
+public interface MicroserviceInstancePing {
+  int getOrder();
+
+  /**
+   * check if this instance if valid to use
+   * @param instance
+   * @return
+   */
+  boolean ping(MicroserviceInstance instance);
+}
diff --git 
a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java
 
b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java
index 0b818df..00b5bc3 100644
--- 
a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java
+++ 
b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java
@@ -23,12 +23,15 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
 import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
+import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
 import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.api.Const;
 import 
org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 import 
org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstanceStatus;
+import org.apache.servicecomb.serviceregistry.api.registry.ServiceCenterConfig;
 import 
org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent;
 import 
org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
+import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
 import org.apache.servicecomb.serviceregistry.definition.DefinitionConst;
 import 
org.apache.servicecomb.serviceregistry.task.event.PullMicroserviceVersionsInstancesEvent;
 import org.slf4j.Logger;
@@ -144,12 +147,7 @@ public class MicroserviceVersions {
 
   private void setInstances(List<MicroserviceInstance> pulledInstances, String 
rev) {
     synchronized (lock) {
-      instances = pulledInstances
-          .stream()
-          .filter(instance -> {
-            return MicroserviceInstanceStatus.UP.equals(instance.getStatus());
-          })
-          .collect(Collectors.toList());
+      instances = mergeInstances(pulledInstances, instances);
       for (MicroserviceInstance instance : instances) {
         // ensure microserviceVersion exists
         versions.computeIfAbsent(instance.getServiceId(), microserviceId -> {
@@ -169,6 +167,28 @@ public class MicroserviceVersions {
     }
   }
 
+  private List<MicroserviceInstance> mergeInstances(List<MicroserviceInstance> 
pulledInstances,
+      List<MicroserviceInstance> inUseInstances) {
+    List<MicroserviceInstance> upInstances = pulledInstances
+        .stream()
+        .filter(instance -> {
+          return MicroserviceInstanceStatus.UP.equals(instance.getStatus());
+        })
+        .collect(Collectors.toList());
+    if (inUseInstances != null && 
ServiceRegistryConfig.INSTANCE.isInstanceRemoveProtectionEnabled()) {
+      MicroserviceInstancePing ping = 
SPIServiceUtils.getPriorityHighestService(MicroserviceInstancePing.class);
+      inUseInstances.stream()
+          .forEach(instance -> {
+            if (!upInstances.contains(instance)) {
+              if (ping.ping(instance)) {
+                upInstances.add(instance);
+              }
+            }
+          });
+    }
+    return upInstances;
+  }
+
   public MicroserviceVersionRule getOrCreateMicroserviceVersionRule(String 
versionRule) {
     // do not use computeIfAbsent
     MicroserviceVersionRule microserviceVersionRule = 
versionRules.get(versionRule);
diff --git 
a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/SimpleMicroserviceInstancePing.java
 
b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/SimpleMicroserviceInstancePing.java
new file mode 100644
index 0000000..9520e08
--- /dev/null
+++ 
b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/SimpleMicroserviceInstancePing.java
@@ -0,0 +1,47 @@
+/*
+ * 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.servicecomb.serviceregistry.consumer;
+
+import java.io.IOException;
+import java.net.Socket;
+
+import org.apache.servicecomb.foundation.common.net.IpPort;
+import org.apache.servicecomb.foundation.common.net.NetUtils;
+import 
org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+
+/**
+ * Simple implementation of .MicroserviceInstancePing using telnet
+ */
+public class SimpleMicroserviceInstancePing implements 
MicroserviceInstancePing {
+  @Override
+  public int getOrder() {
+    return 100;
+  }
+
+  @Override
+  public boolean ping(MicroserviceInstance instance) {
+    if (instance.getEndpoints() != null && instance.getEndpoints().size() > 0) 
{
+      IpPort ipPort = 
NetUtils.parseIpPortFromURI(instance.getEndpoints().get(0));
+      try (Socket s = new Socket(ipPort.getHostOrIp(), ipPort.getPort())) {
+        return true;
+      } catch (IOException e) {
+        // ignore this error
+      }
+    }
+    return false;
+  }
+}
diff --git 
a/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing
 
b/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing
new file mode 100644
index 0000000..ce06621
--- /dev/null
+++ 
b/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.apache.servicecomb.serviceregistry.consumer.SimpleMicroserviceInstancePing
\ No newline at end of file
diff --git 
a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroServiceInstance.java
 
b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroServiceInstance.java
index 4d4ddc6..affcf92 100644
--- 
a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroServiceInstance.java
+++ 
b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroServiceInstance.java
@@ -97,6 +97,16 @@ public class TestMicroServiceInstance {
     Assert.assertEquals(MicroserviceInstanceStatus.DOWN, 
oMicroserviceInstance.getStatus());
     Assert.assertEquals("Test", oMicroserviceInstance.getStage());
     Assert.assertEquals("china", 
oMicroserviceInstance.getProperties().get("region"));
+
+    Assert.assertEquals(oMicroserviceInstance, oMicroserviceInstance);
+    MicroserviceInstance other = new MicroserviceInstance();
+    other.setInstanceId("testInstanceIDOther");
+    MicroserviceInstance same = new MicroserviceInstance();
+    same.setInstanceId("testInstanceID");
+    Assert.assertNotEquals(oMicroserviceInstance, other);
+    Assert.assertNotEquals(oMicroserviceInstance.hashCode(), other.hashCode());
+    Assert.assertEquals(oMicroserviceInstance, same);
+    Assert.assertEquals(oMicroserviceInstance.hashCode(), same.hashCode());
   }
 
   @SuppressWarnings("deprecation")
diff --git 
a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java
 
b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java
index 24b566f..88ba8bf 100644
--- 
a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java
+++ 
b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java
@@ -134,6 +134,7 @@ public class LocalServiceRegistryClientImplTest {
     mockRegisterMicroservice(appId, microserviceName, "2.0.0");
 
     MicroserviceInstance instance = new MicroserviceInstance();
+    instance.setInstanceId("testid");
     instance.setServiceId(v1.getServiceId());
     registryClient.registerMicroserviceInstance(instance);
 
diff --git 
a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersions.java
 
b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersions.java
index b336d88..53e1f38 100644
--- 
a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersions.java
+++ 
b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersions.java
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
 import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.api.Const;
 import org.apache.servicecomb.serviceregistry.api.MicroserviceKey;
@@ -77,6 +78,7 @@ public class TestMicroserviceVersions {
 
   @After
   public void tearDown() throws Exception {
+    ArchaiusUtils.resetConfig();
     findInstancesResponse = null;
     microserviceInstances = null;
   }
@@ -149,6 +151,17 @@ public class TestMicroserviceVersions {
   }
 
   @Test
+  public void submitPullProtection() {
+    
ArchaiusUtils.setProperty("servicecomb.service.registry.instance.remove.protection",
 true);
+    String microserviceId = "1";
+    setup(microserviceId);
+    microserviceVersions.submitPull();
+    microserviceVersions.submitPull();
+    MicroserviceVersionRule versionRule = 
microserviceVersions.getOrCreateMicroserviceVersionRule("0+");
+    Assert.assertSame(versionRule.getInstances().entrySet().size(), 1);
+  }
+
+  @Test
   public void pullInstancesCancel() {
     new MockUp<RegistryUtils>() {
       @Mock
diff --git 
a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestSimpleMicroserviceInstancePing.java
 
b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestSimpleMicroserviceInstancePing.java
new file mode 100644
index 0000000..f4403d8
--- /dev/null
+++ 
b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestSimpleMicroserviceInstancePing.java
@@ -0,0 +1,46 @@
+/*
+ * 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.servicecomb.serviceregistry.consumer;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.ArrayList;
+import java.util.List;
+
+import 
org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestSimpleMicroserviceInstancePing {
+  @Test
+  public void testPing() throws IOException {
+    SimpleMicroserviceInstancePing ping = new SimpleMicroserviceInstancePing();
+    Assert.assertEquals(ping.getOrder(), 100);
+    MicroserviceInstance instance = new MicroserviceInstance();
+    List<String> endpoints = new ArrayList<>();
+    ServerSocket ss = new ServerSocket(35677);
+
+    endpoints.add("http://localhost:35677";);
+    instance.setEndpoints(endpoints);
+    Assert.assertTrue(ping.ping(instance));
+    MicroserviceInstance instance2 = new MicroserviceInstance();
+    Assert.assertFalse(ping.ping(instance2));
+    ss.close();
+    Assert.assertFalse(ping.ping(instance));
+  }
+}
diff --git 
a/spring-boot-starter/spring-boot-starter-transport/src/test/java/org/apache/servicecomb/springboot/starter/transport/TestRestServletInitializer.java
 
b/spring-boot-starter/spring-boot-starter-transport/src/test/java/org/apache/servicecomb/springboot/starter/transport/TestRestServletInitializer.java
index 8952d2b..bb26648 100644
--- 
a/spring-boot-starter/spring-boot-starter-transport/src/test/java/org/apache/servicecomb/springboot/starter/transport/TestRestServletInitializer.java
+++ 
b/spring-boot-starter/spring-boot-starter-transport/src/test/java/org/apache/servicecomb/springboot/starter/transport/TestRestServletInitializer.java
@@ -51,7 +51,7 @@ public class TestRestServletInitializer {
 
   private static final String LISTEN_ADDRESS = "127.0.0.1";
 
-  private static final int TEST_PORT = 8080;
+  private static final int TEST_PORT = 8582;
 
   @BeforeClass
   public static void beforeClass() {

-- 
To stop receiving notification emails like this one, please contact
liu...@apache.org.

Reply via email to