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

albumenj pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/master by this push:
     new e6148ac  fix: Fix the problem of wrong number of retries in failback 
mode (#9525)
e6148ac is described below

commit e6148ac06e2cca6b2705fd590d5dead1e15e1cd7
Author: 桔子 <[email protected]>
AuthorDate: Sun Jan 23 16:58:22 2022 +0800

    fix: Fix the problem of wrong number of retries in failback mode (#9525)
    
    When the retries value is zero,
    the logic in failback mode resets it to the default value of 3,
    making it impossible to turn off the retry mechanism.
    
    Fixes #9522
---
 .../cluster/support/FailbackClusterInvoker.java    | 21 ++++-
 .../support/FailbackClusterInvokerTest.java        | 96 ++++++++++++++++++++++
 2 files changed, 113 insertions(+), 4 deletions(-)

diff --git 
a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvoker.java
 
b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvoker.java
index 0d2d6d1..cbbe853 100644
--- 
a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvoker.java
+++ 
b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvoker.java
@@ -52,6 +52,9 @@ public class FailbackClusterInvoker<T> extends 
AbstractClusterInvoker<T> {
 
     private static final long RETRY_FAILED_PERIOD = 5;
 
+    /**
+     * Number of retries obtained from the configuration, don't contain the 
first invoke.
+     */
     private final int retries;
 
     private final int failbackTasks;
@@ -62,7 +65,7 @@ public class FailbackClusterInvoker<T> extends 
AbstractClusterInvoker<T> {
         super(directory);
 
         int retriesConfig = getUrl().getParameter(RETRIES_KEY, 
DEFAULT_FAILBACK_TIMES);
-        if (retriesConfig <= 0) {
+        if (retriesConfig < 0) {
             retriesConfig = DEFAULT_FAILBACK_TIMES;
         }
         int failbackTasksConfig = getUrl().getParameter(FAIL_BACK_TASKS_KEY, 
DEFAULT_FAILBACK_TASKS);
@@ -124,10 +127,18 @@ public class FailbackClusterInvoker<T> extends 
AbstractClusterInvoker<T> {
         private final Invocation invocation;
         private final LoadBalance loadbalance;
         private final List<Invoker<T>> invokers;
-        private final int retries;
         private final long tick;
         private Invoker<T> lastInvoker;
-        private int retryTimes = 0;
+
+        /**
+         * Number of retries obtained from the configuration, don't contain 
the first invoke.
+         */
+        private final int retries;
+
+        /**
+         * Number of retried.
+         */
+        private int retriedTimes = 0;
 
         RetryTimerTask(LoadBalance loadbalance, Invocation invocation, 
List<Invoker<T>> invokers, Invoker<T> lastInvoker, int retries, long tick) {
             this.loadbalance = loadbalance;
@@ -141,12 +152,14 @@ public class FailbackClusterInvoker<T> extends 
AbstractClusterInvoker<T> {
         @Override
         public void run(Timeout timeout) {
             try {
+                logger.info("Attempt to retry to invoke method " + 
invocation.getMethodName() +
+                        ". The total will retry " + retries + " times, the 
current is the " + retriedTimes + " retry");
                 Invoker<T> retryInvoker = select(loadbalance, invocation, 
invokers, Collections.singletonList(lastInvoker));
                 lastInvoker = retryInvoker;
                 retryInvoker.invoke(invocation);
             } catch (Throwable e) {
                 logger.error("Failed retry to invoke method " + 
invocation.getMethodName() + ", waiting again.", e);
-                if ((++retryTimes) >= retries) {
+                if ((++retriedTimes) >= retries) {
                     logger.error("Failed retry times exceed threshold (" + 
retries + "), We have to abandon, invocation->" + invocation);
                 } else {
                     rePut(timeout);
diff --git 
a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java
 
b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java
index d648943..489a921 100644
--- 
a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java
+++ 
b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java
@@ -18,6 +18,7 @@
 package org.apache.dubbo.rpc.cluster.support;
 
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.common.utils.DubboAppender;
 import org.apache.dubbo.common.utils.LogUtil;
 import org.apache.dubbo.rpc.AppResponse;
@@ -37,11 +38,13 @@ import org.junit.jupiter.api.Order;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestMethodOrder;
 
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import static org.apache.dubbo.common.constants.CommonConstants.RETRIES_KEY;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.Mockito.mock;
@@ -174,4 +177,97 @@ public class FailbackClusterInvokerTest {
         Assertions.assertEquals(1, LogUtil.findMessage(Level.ERROR, "Failback 
background works error"), "must have one error message ");
         // it can be invoke successfully
     }
+
+
+    private long getRetryFailedPeriod() throws NoSuchFieldException, 
IllegalAccessException {
+        Field retryFailedPeriod = 
FailbackClusterInvoker.class.getDeclaredField("RETRY_FAILED_PERIOD");
+        retryFailedPeriod.setAccessible(true);
+        return retryFailedPeriod.getLong(FailbackClusterInvoker.class);
+    }
+
+    @Test
+    @Order(5)
+    public void testInvokeRetryTimesWithZeroValue() throws 
InterruptedException, NoSuchFieldException,
+            IllegalAccessException {
+        int retries = 0;
+        resetInvokerToException();
+        given(dic.getConsumerUrl()).willReturn(url.addParameter(RETRIES_KEY, 
retries));
+
+        FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new 
FailbackClusterInvoker<>(dic);
+        LogUtil.start();
+        DubboAppender.clear();
+
+        invocation.setMethodName("testInvokeRetryTimesWithZeroValue");
+        invoker.invoke(invocation);
+
+        CountDownLatch countDown = new CountDownLatch(1);
+        countDown.await(getRetryFailedPeriod() * (retries + 1), 
TimeUnit.SECONDS);
+        LogUtil.stop();
+        Assertions.assertEquals(0, LogUtil.findMessage(Level.INFO, "Attempt to 
retry to invoke method " +
+                "testInvokeRetryTimesWithZeroValue"), "No retry messages 
allowed");
+    }
+
+    @Test
+    @Order(6)
+    public void testInvokeRetryTimesWithTwoValue() throws 
InterruptedException, NoSuchFieldException,
+            IllegalAccessException {
+        int retries = 2;
+        resetInvokerToException();
+        given(dic.getConsumerUrl()).willReturn(url.addParameter(RETRIES_KEY, 
retries));
+
+        FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new 
FailbackClusterInvoker<>(dic);
+        LogUtil.start();
+        DubboAppender.clear();
+
+        invocation.setMethodName("testInvokeRetryTimesWithTwoValue");
+        invoker.invoke(invocation);
+
+        CountDownLatch countDown = new CountDownLatch(1);
+        countDown.await(getRetryFailedPeriod() * (retries + 1), 
TimeUnit.SECONDS);
+        LogUtil.stop();
+        Assertions.assertEquals(2, LogUtil.findMessage(Level.INFO, "Attempt to 
retry to invoke method " +
+                "testInvokeRetryTimesWithTwoValue"), "Must have two error 
message ");
+    }
+
+    @Test
+    @Order(7)
+    public void testInvokeRetryTimesWithDefaultValue() throws 
InterruptedException, NoSuchFieldException,
+            IllegalAccessException {
+        resetInvokerToException();
+        
given(dic.getConsumerUrl()).willReturn(URL.valueOf("test://test:11/test"));
+
+        FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new 
FailbackClusterInvoker<>(dic);
+        LogUtil.start();
+        DubboAppender.clear();
+
+        invocation.setMethodName("testInvokeRetryTimesWithDefaultValue");
+        invoker.invoke(invocation);
+
+        CountDownLatch countDown = new CountDownLatch(1);
+        countDown.await(getRetryFailedPeriod() * 
(CommonConstants.DEFAULT_FAILBACK_TIMES + 1), TimeUnit.SECONDS);
+        LogUtil.stop();
+        Assertions.assertEquals(3, LogUtil.findMessage(Level.INFO, "Attempt to 
retry to invoke method " +
+                "testInvokeRetryTimesWithDefaultValue"), "Must have three 
error message ");
+    }
+
+    @Test
+    @Order(8)
+    public void testInvokeRetryTimesWithIllegalValue() throws 
InterruptedException, NoSuchFieldException,
+            IllegalAccessException {
+        resetInvokerToException();
+        given(dic.getConsumerUrl()).willReturn(url.addParameter(RETRIES_KEY, 
-100));
+
+        FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new 
FailbackClusterInvoker<>(dic);
+        LogUtil.start();
+        DubboAppender.clear();
+
+        invocation.setMethodName("testInvokeRetryTimesWithIllegalValue");
+        invoker.invoke(invocation);
+
+        CountDownLatch countDown = new CountDownLatch(1);
+        countDown.await(getRetryFailedPeriod() * 
(CommonConstants.DEFAULT_FAILBACK_TIMES + 1), TimeUnit.SECONDS);
+        LogUtil.stop();
+        Assertions.assertEquals(3, LogUtil.findMessage(Level.INFO, "Attempt to 
retry to invoke method " +
+                "testInvokeRetryTimesWithIllegalValue"), "Must have three 
error message ");
+    }
 }
\ No newline at end of file

Reply via email to