From e0f488161a67581ea4d5fe69492c62df33646937 Mon Sep 17 00:00:00 2001 From: TomlongTK Date: Mon, 22 Jul 2024 11:51:35 +0800 Subject: [PATCH] Failover retry extension --- .../support/DefaultRetryableFunction.java | 27 +++++++++++++++++++ .../support/FailoverClusterInvoker.java | 26 ++++++++++-------- .../cluster/support/RetryableFunction.java | 26 ++++++++++++++++++ ...ubbo.rpc.cluster.support.RetryableFunction | 1 + .../common/constants/CommonConstants.java | 2 ++ dubbo-distribution/dubbo-all/pom.xml | 4 +++ 6 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/DefaultRetryableFunction.java create mode 100644 dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/RetryableFunction.java create mode 100644 dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.support.RetryableFunction diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/DefaultRetryableFunction.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/DefaultRetryableFunction.java new file mode 100644 index 000000000000..06c1c582cdcc --- /dev/null +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/DefaultRetryableFunction.java @@ -0,0 +1,27 @@ +/* + * 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.dubbo.rpc.cluster.support; + +import org.apache.dubbo.rpc.RpcException; + +public class DefaultRetryableFunction implements RetryableFunction{ + + @Override + public boolean retryable(RpcException e) { + return !e.isBiz(); + } +} diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java index 1fc3cadcc111..7cebc7986a23 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java @@ -34,8 +34,10 @@ import java.util.List; import java.util.Set; +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_RETRIES; import static org.apache.dubbo.common.constants.CommonConstants.RETRIES_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.RETRYABLE_FUNCTION_KEY; import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_MULTIPLE_RETRIES; /** @@ -50,8 +52,13 @@ public class FailoverClusterInvoker extends AbstractClusterInvoker { private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(FailoverClusterInvoker.class); + private final RetryableFunction retryableFunction; + public FailoverClusterInvoker(Directory directory) { super(directory); + this.retryableFunction = getUrl().getOrDefaultApplicationModel() + .getExtensionLoader(RetryableFunction.class) + .getOrDefaultExtension(getUrl().getParameter(RETRYABLE_FUNCTION_KEY, DEFAULT_KEY)); } @Override @@ -77,7 +84,6 @@ public Result doInvoke(Invocation invocation, final List> invokers, L Invoker invoker = select(loadbalance, invocation, copyInvokers, invoked); invoked.add(invoker); RpcContext.getServiceContext().setInvokers((List) invoked); - boolean success = false; try { Result result = invokeWithContext(invoker, invocation); if (le != null && logger.isWarnEnabled()) { @@ -98,18 +104,16 @@ public Result doInvoke(Invocation invocation, final List> invokers, L + le.getMessage(), le); } - success = true; return result; - } catch (RpcException e) { - if (e.isBiz()) { // biz exception. - throw e; + } catch (Throwable t) { + providers.add(invoker.getUrl().getAddress()); + if (t instanceof RpcException) { + le = (RpcException) t; + } else { + le = new RpcException(t.getMessage(), t); } - le = e; - } catch (Throwable e) { - le = new RpcException(e.getMessage(), e); - } finally { - if (!success) { - providers.add(invoker.getUrl().getAddress()); + if (!retryableFunction.retryable(le)) { + throw le; } } } diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/RetryableFunction.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/RetryableFunction.java new file mode 100644 index 000000000000..99b66ef35f51 --- /dev/null +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/RetryableFunction.java @@ -0,0 +1,26 @@ +/* + * 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.dubbo.rpc.cluster.support; + +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.rpc.RpcException; + +@SPI +public interface RetryableFunction { + + boolean retryable(RpcException e); +} diff --git a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.support.RetryableFunction b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.support.RetryableFunction new file mode 100644 index 000000000000..772adc686bd0 --- /dev/null +++ b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.support.RetryableFunction @@ -0,0 +1 @@ +default=org.apache.dubbo.rpc.cluster.support.DefaultRetryableFunction diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java index 704b30c74cdd..294e1829d271 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java @@ -670,4 +670,6 @@ public interface CommonConstants { String ZOOKEEPER_ENSEMBLE_TRACKER_KEY = "zookeeper.ensemble.tracker"; String DUBBO_VERSIONS_KEY = "META-INF/dubbo-versions"; + + String RETRYABLE_FUNCTION_KEY = "retryable-function"; } diff --git a/dubbo-distribution/dubbo-all/pom.xml b/dubbo-distribution/dubbo-all/pom.xml index 783dbbe1a9dc..4bb9fd877637 100644 --- a/dubbo-distribution/dubbo-all/pom.xml +++ b/dubbo-distribution/dubbo-all/pom.xml @@ -938,6 +938,10 @@ META-INF/dubbo/internal/org.apache.dubbo.registry.integration.ServiceURLCustomizer + + + META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.support.RetryableFunction +