You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by wu...@apache.org on 2018/10/26 02:30:07 UTC

[incubator-servicecomb-java-chassis] branch master updated: [SCB-975] add some special exception to loadbalance default retry handler's exception pool, such as IOException and VertxException

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

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


The following commit(s) were added to refs/heads/master by this push:
     new b6d1697  [SCB-975] add some special exception to loadbalance default retry handler's exception pool, such as IOException and VertxException
b6d1697 is described below

commit b6d169702709d1de0e06953be7de4460bce46d65
Author: weixing <je...@163.com>
AuthorDate: Tue Oct 23 22:11:01 2018 +0800

    [SCB-975] add some special exception to loadbalance default retry handler's exception pool, such as IOException and VertxException
---
 .../loadbalance/DefaultRetryExtensionsFactory.java |  44 +++++++-
 .../loadbalance/TestDefaultRetryhandler.java       | 117 +++++++++++++++++++++
 2 files changed, 159 insertions(+), 2 deletions(-)

diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/DefaultRetryExtensionsFactory.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/DefaultRetryExtensionsFactory.java
index ea23aca..5a61dc7 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/DefaultRetryExtensionsFactory.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/DefaultRetryExtensionsFactory.java
@@ -16,18 +16,23 @@
  */
 package org.apache.servicecomb.loadbalance;
 
+import java.io.IOException;
 import java.net.ConnectException;
 import java.net.SocketTimeoutException;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.springframework.stereotype.Component;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.netflix.client.DefaultLoadBalancerRetryHandler;
 import com.netflix.client.RetryHandler;
-import com.netflix.client.Utils;
+
+import io.vertx.core.VertxException;
 
 @Component
 public class DefaultRetryExtensionsFactory implements ExtensionsFactory {
@@ -52,9 +57,20 @@ public class DefaultRetryExtensionsFactory implements ExtensionsFactory {
       private List<Class<? extends Throwable>> retriable = Lists
           .newArrayList(new Class[] {ConnectException.class, SocketTimeoutException.class});
 
+      Map<Class<? extends Throwable>, List<String>> strictRetriable =
+          ImmutableMap.<Class<? extends Throwable>, List<String>>builder()
+              .put(ConnectException.class, Lists.newArrayList())
+              .put(SocketTimeoutException.class, Lists.newArrayList())
+              /*
+               * deal with some special exceptions caused by the server side close the connection 
+               */
+              .put(IOException.class, Lists.newArrayList(new String[] {"Connection reset by peer"}))
+              .put(VertxException.class, Lists.newArrayList(new String[] {"Connection was closed"}))
+              .build();
+
       @Override
       public boolean isRetriableException(Throwable e, boolean sameServer) {
-        boolean retriable = Utils.isPresentAsCause(e, getRetriableExceptions());
+        boolean retriable = isPresentAsCause(e);
         if (!retriable) {
           if (e instanceof InvocationException) {
             if (((InvocationException) e).getStatusCode() == 503) {
@@ -69,6 +85,30 @@ public class DefaultRetryExtensionsFactory implements ExtensionsFactory {
       protected List<Class<? extends Throwable>> getRetriableExceptions() {
         return this.retriable;
       }
+
+      public boolean isPresentAsCause(Throwable throwableToSearchIn) {
+        int infiniteLoopPreventionCounter = 10;
+        while (throwableToSearchIn != null && infiniteLoopPreventionCounter > 0) {
+          infiniteLoopPreventionCounter--;
+          for (Entry<Class<? extends Throwable>, List<String>> c : strictRetriable.entrySet()) {
+            Class<? extends Throwable> key = c.getKey();
+            if (key.isAssignableFrom(throwableToSearchIn.getClass())) {
+              if (c.getValue() == null || c.getValue().isEmpty()) {
+                return true;
+              } else {
+                String msg = throwableToSearchIn.getMessage();
+                for (String val : c.getValue()) {
+                  if (val.equals(msg)) {
+                    return true;
+                  }
+                }
+              }
+            }
+          }
+          throwableToSearchIn = throwableToSearchIn.getCause();
+        }
+        return false;
+      }
     };
   }
 }
diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestDefaultRetryhandler.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestDefaultRetryhandler.java
new file mode 100644
index 0000000..8535a5a
--- /dev/null
+++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestDefaultRetryhandler.java
@@ -0,0 +1,117 @@
+/*
+ * 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.loadbalance;
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.SocketTimeoutException;
+
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.netflix.client.RetryHandler;
+
+import io.vertx.core.VertxException;
+
+public class TestDefaultRetryhandler {
+
+  private static final String RETYR_NAME = "default";
+
+  private static final String MICROSERVICE_NAME = "servicename";
+
+  private RetryHandler retryHandler;
+
+  @Before
+  public void setup() {
+    DefaultRetryExtensionsFactory factory = new DefaultRetryExtensionsFactory();
+    retryHandler = factory.createRetryHandler(RETYR_NAME, MICROSERVICE_NAME);
+  }
+
+  @Test
+  public void testRetryWithConnectionException() {
+    Exception target = new ConnectException("connectin refused");
+    Exception root = new Exception(target);
+    boolean retriable = retryHandler.isRetriableException(root, false);
+    Assert.assertTrue(retriable);
+  }
+
+  @Test
+  public void testRetryWithSocketTimeout() {
+    Exception target = new SocketTimeoutException("Read timed out");
+    Exception root = new Exception(target);
+    boolean retriable = retryHandler.isRetriableException(root, false);
+    Assert.assertTrue(retriable);
+  }
+
+  @Test
+  public void testRetryWithIOException() {
+    Exception target = new IOException("Connection reset by peer");
+    Exception root = new Exception(target);
+    boolean retriable = retryHandler.isRetriableException(root, false);
+    Assert.assertTrue(retriable);
+
+    target = new IOException("Target not exist");
+    root = new Exception(target);
+    retriable = retryHandler.isRetriableException(root, false);
+    Assert.assertFalse(retriable);
+  }
+
+  @Test
+  public void testRetryVertxException() {
+    Exception target = new VertxException("Connection was closed");
+    Exception root = new Exception(target);
+    boolean retriable = retryHandler.isRetriableException(root, false);
+    Assert.assertTrue(retriable);
+
+    target = new IOException("");
+    root = new Exception(target);
+    retriable = retryHandler.isRetriableException(root, false);
+    Assert.assertFalse(retriable);
+  }
+
+  @Test
+  public void testRetryInvocation503() {
+    Exception root = new InvocationException(503, "Service Unavailable", "Error");
+    boolean retriable = retryHandler.isRetriableException(root, false);
+    Assert.assertTrue(retriable);
+  }
+
+  @Test
+  public void testRetryEqualTen() {
+    Exception target = new ConnectException("connectin refused");
+    for (int i = 0; i < 8; i++) {
+      target = new Exception("Level" + i, target);
+    }
+    Exception root = new Exception(target);
+    boolean retriable = retryHandler.isRetriableException(root, false);
+    Assert.assertTrue(retriable);
+  }
+  
+  @Test
+  public void testRetryOverTen() {
+    Exception target = new ConnectException("connectin refused");
+    for (int i = 0; i < 9; i++) {
+      target = new Exception("Level" + i, target);
+    }
+    Exception root = new Exception(target);
+    boolean retriable = retryHandler.isRetriableException(root, false);
+    Assert.assertFalse(retriable);
+  }
+}