Skip to content

Commit

Permalink
[3.0] Add router fail fast option (#9388)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlbumenJ authored Dec 12, 2021
1 parent 304d5ac commit 312dd2b
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,6 @@ public interface Constants {
* The key of shortestResponseSlidePeriod
*/
String SHORTEST_RESPONSE_SLIDE_PERIOD = "shortestResponseSlidePeriod";

String SHOULD_FAIL_FAST_KEY = "dubbo.router.should-fail-fast";
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils;
Expand All @@ -30,6 +31,7 @@
import org.apache.dubbo.rpc.cluster.router.state.StateRouter;
import org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;
import org.apache.dubbo.rpc.cluster.router.state.StateRouterResult;
import org.apache.dubbo.rpc.model.ModuleModel;

import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -63,12 +65,19 @@ public class RouterChain<T> {
private volatile List<StateRouter<T>> builtinStateRouters = Collections.emptyList();
private volatile List<StateRouter<T>> stateRouters = Collections.emptyList();

/**
* Should continue route if current router's result is empty
*/
private final boolean shouldFailFast;

public static <T> RouterChain<T> buildChain(Class<T> interfaceClass, URL url) {
return new RouterChain<>(interfaceClass, url);
}

private RouterChain(Class<T> interfaceClass, URL url) {
List<RouterFactory> extensionFactories = url.getOrDefaultApplicationModel().getExtensionLoader(RouterFactory.class)
ModuleModel moduleModel = url.getOrDefaultModuleModel();

List<RouterFactory> extensionFactories = moduleModel.getExtensionLoader(RouterFactory.class)
.getActivateExtension(url, ROUTER_KEY);

List<Router> routers = extensionFactories.stream()
Expand All @@ -78,7 +87,7 @@ private RouterChain(Class<T> interfaceClass, URL url) {

initWithRouters(routers);

List<StateRouterFactory> extensionStateRouterFactories = url.getOrDefaultApplicationModel()
List<StateRouterFactory> extensionStateRouterFactories = moduleModel
.getExtensionLoader(StateRouterFactory.class)
.getActivateExtension(url, ROUTER_KEY);

Expand All @@ -89,6 +98,8 @@ private RouterChain(Class<T> interfaceClass, URL url) {

// init state routers
initWithStateRouters(stateRouters);

this.shouldFailFast = Boolean.parseBoolean(ConfigurationUtils.getProperty(moduleModel, Constants.SHOULD_FAIL_FAST_KEY, "true"));
}

/**
Expand Down Expand Up @@ -158,7 +169,7 @@ public List<Invoker<T>> route(URL url, BitList<Invoker<T>> availableInvokers, In
for (StateRouter<T> stateRouter : stateRouters) {
StateRouterResult<Invoker<T>> routeResult = stateRouter.route(resultInvokers, url, invocation, false);
resultInvokers = routeResult.getResult();
if (resultInvokers.isEmpty()) {
if (resultInvokers.isEmpty() && shouldFailFast) {
printRouterSnapshot(url, availableInvokers, invocation);
return BitList.emptyList();
}
Expand All @@ -179,7 +190,7 @@ public List<Invoker<T>> route(URL url, BitList<Invoker<T>> availableInvokers, In
// Copy resultInvokers to a arrayList. BitList not support
RouterResult<Invoker<T>> routeResult = router.route(commonRouterResult, url, invocation, false);
commonRouterResult = routeResult.getResult();
if (CollectionUtils.isEmpty(commonRouterResult)) {
if (CollectionUtils.isEmpty(commonRouterResult) && shouldFailFast) {
printRouterSnapshot(url, availableInvokers, invocation);
return BitList.emptyList();
}
Expand Down Expand Up @@ -222,7 +233,7 @@ public RouterSnapshotNode<T> buildRouterSnapshot(URL url, BitList<Invoker<T>> av
currentNode.setRouterMessage(routerMessage);

// result is empty, log out
if (resultInvokers.isEmpty()) {
if (resultInvokers.isEmpty() && shouldFailFast) {
return snapshotNode;
}

Expand All @@ -248,7 +259,7 @@ public RouterSnapshotNode<T> buildRouterSnapshot(URL url, BitList<Invoker<T>> av
currentNode.setRouterMessage(routerMessage);

// result is empty, log out
if (CollectionUtils.isEmpty(routeResult)) {
if (CollectionUtils.isEmpty(routeResult) && shouldFailFast) {
return snapshotNode;
} else {
commonRouterResult = routeResult;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
Expand All @@ -34,10 +35,12 @@
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Cluster;
import org.apache.dubbo.rpc.cluster.Configurator;
import org.apache.dubbo.rpc.cluster.Constants;
import org.apache.dubbo.rpc.cluster.RouterChain;
import org.apache.dubbo.rpc.cluster.RouterFactory;
import org.apache.dubbo.rpc.cluster.directory.AbstractDirectory;
import org.apache.dubbo.rpc.cluster.router.state.BitList;
import org.apache.dubbo.rpc.model.ModuleModel;

import java.util.List;

Expand Down Expand Up @@ -107,11 +110,18 @@ public abstract class DynamicDirectory<T> extends AbstractDirectory<T> implement

protected ServiceInstancesChangedListener serviceListener;

/**
* Should continue route if directory is empty
*/
private final boolean shouldFailFast;

public DynamicDirectory(Class<T> serviceType, URL url) {
super(url, true);

this.cluster = url.getOrDefaultApplicationModel().getExtensionLoader(Cluster.class).getAdaptiveExtension();
this.routerFactory = url.getOrDefaultApplicationModel().getExtensionLoader(RouterFactory.class).getAdaptiveExtension();
ModuleModel moduleModel = url.getOrDefaultModuleModel();

this.cluster = moduleModel.getExtensionLoader(Cluster.class).getAdaptiveExtension();
this.routerFactory = moduleModel.getExtensionLoader(RouterFactory.class).getAdaptiveExtension();

if (serviceType == null) {
throw new IllegalArgumentException("service type is null.");
Expand All @@ -130,6 +140,8 @@ public DynamicDirectory(Class<T> serviceType, URL url) {
this.directoryUrl = consumerUrl;
String group = directoryUrl.getGroup("");
this.multiGroup = group != null && (ANY_VALUE.equals(group) || group.contains(","));

this.shouldFailFast = Boolean.parseBoolean(ConfigurationUtils.getProperty(moduleModel, Constants.SHOULD_FAIL_FAST_KEY, "true"));
}

@Override
Expand Down Expand Up @@ -165,7 +177,7 @@ public void unSubscribe(URL url) {

@Override
public List<Invoker<T>> doList(BitList<Invoker<T>> invokers, Invocation invocation) {
if (forbidden) {
if (forbidden && shouldFailFast) {
// 1. No service provider 2. Service providers are disabled
throw new RpcException(RpcException.FORBIDDEN_EXCEPTION, "No provider available from registry " +
getUrl().getAddress() + " for service " + getConsumerUrl().getServiceKey() + " on consumer " +
Expand Down

0 comments on commit 312dd2b

Please sign in to comment.