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