mirror of https://github.com/grpc/grpc-java.git
xds: parse timeout from RDS responses (#7257)
This commit is contained in:
parent
800ef216a8
commit
14af76cab1
|
|
@ -26,6 +26,7 @@ import com.google.protobuf.ListValue;
|
|||
import com.google.protobuf.NullValue;
|
||||
import com.google.protobuf.Struct;
|
||||
import com.google.protobuf.Value;
|
||||
import com.google.protobuf.util.Durations;
|
||||
import com.google.re2j.Pattern;
|
||||
import com.google.re2j.PatternSyntaxException;
|
||||
import io.envoyproxy.envoy.type.v3.FractionalPercent;
|
||||
|
|
@ -40,6 +41,7 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
|
|
@ -1067,6 +1069,7 @@ final class EnvoyProtoData {
|
|||
|
||||
/** See corresponding Envoy proto message {@link io.envoyproxy.envoy.api.v2.route.RouteAction}. */
|
||||
static final class RouteAction {
|
||||
private final long timeoutNano;
|
||||
// Exactly one of the following fields is non-null.
|
||||
@Nullable
|
||||
private final String cluster;
|
||||
|
|
@ -1074,11 +1077,20 @@ final class EnvoyProtoData {
|
|||
private final List<ClusterWeight> weightedClusters;
|
||||
|
||||
@VisibleForTesting
|
||||
RouteAction(@Nullable String cluster, @Nullable List<ClusterWeight> weightedClusters) {
|
||||
RouteAction(
|
||||
long timeoutNano,
|
||||
@Nullable String cluster,
|
||||
@Nullable List<ClusterWeight> weightedClusters) {
|
||||
this.timeoutNano = timeoutNano;
|
||||
this.cluster = cluster;
|
||||
this.weightedClusters = weightedClusters;
|
||||
}
|
||||
|
||||
|
||||
Long getTimeoutNano() {
|
||||
return timeoutNano;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getCluster() {
|
||||
return cluster;
|
||||
|
|
@ -1098,18 +1110,20 @@ final class EnvoyProtoData {
|
|||
return false;
|
||||
}
|
||||
RouteAction that = (RouteAction) o;
|
||||
return Objects.equals(cluster, that.cluster)
|
||||
return Objects.equals(timeoutNano, that.timeoutNano)
|
||||
&& Objects.equals(cluster, that.cluster)
|
||||
&& Objects.equals(weightedClusters, that.weightedClusters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(cluster, weightedClusters);
|
||||
return Objects.hash(timeoutNano, cluster, weightedClusters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ToStringHelper toStringHelper = MoreObjects.toStringHelper(this);
|
||||
toStringHelper.add("timeout", timeoutNano + "ns");
|
||||
if (cluster != null) {
|
||||
toStringHelper.add("cluster", cluster);
|
||||
}
|
||||
|
|
@ -1146,7 +1160,16 @@ final class EnvoyProtoData {
|
|||
return StructOrError.fromError(
|
||||
"Unknown cluster specifier: " + proto.getClusterSpecifierCase());
|
||||
}
|
||||
return StructOrError.fromStruct(new RouteAction(cluster, weightedClusters));
|
||||
long timeoutNano = TimeUnit.SECONDS.toNanos(15L); // default 15s
|
||||
if (proto.hasMaxGrpcTimeout()) {
|
||||
timeoutNano = Durations.toNanos(proto.getMaxGrpcTimeout());
|
||||
} else if (proto.hasTimeout()) {
|
||||
timeoutNano = Durations.toNanos(proto.getTimeout());
|
||||
}
|
||||
if (timeoutNano == 0) {
|
||||
timeoutNano = Long.MAX_VALUE;
|
||||
}
|
||||
return StructOrError.fromStruct(new RouteAction(timeoutNano, cluster, weightedClusters));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import com.google.protobuf.BoolValue;
|
|||
import com.google.protobuf.Struct;
|
||||
import com.google.protobuf.UInt32Value;
|
||||
import com.google.protobuf.Value;
|
||||
import com.google.protobuf.util.Durations;
|
||||
import com.google.re2j.Pattern;
|
||||
import io.envoyproxy.envoy.config.core.v3.RuntimeFractionalPercent;
|
||||
import io.envoyproxy.envoy.config.route.v3.QueryParameterMatcher;
|
||||
|
|
@ -44,6 +45,7 @@ import io.grpc.xds.RouteMatch.HeaderMatcher;
|
|||
import io.grpc.xds.RouteMatch.PathMatcher;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.Nullable;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
|
@ -206,7 +208,7 @@ public class EnvoyProtoDataTest {
|
|||
new Route(
|
||||
new RouteMatch(new PathMatcher("/service/method", null, null),
|
||||
Collections.<HeaderMatcher>emptyList(), null),
|
||||
new RouteAction("cluster-foo", null)));
|
||||
new RouteAction(TimeUnit.SECONDS.toNanos(15L), "cluster-foo", null)));
|
||||
|
||||
io.envoyproxy.envoy.config.route.v3.Route unsupportedProto =
|
||||
io.envoyproxy.envoy.config.route.v3.Route.newBuilder()
|
||||
|
|
@ -393,27 +395,51 @@ public class EnvoyProtoDataTest {
|
|||
|
||||
@Test
|
||||
public void convertRouteAction() {
|
||||
// cluster_specifier = cluster
|
||||
// cluster_specifier = cluster, default timeout
|
||||
io.envoyproxy.envoy.config.route.v3.RouteAction proto1 =
|
||||
io.envoyproxy.envoy.config.route.v3.RouteAction.newBuilder()
|
||||
.setCluster("cluster-foo")
|
||||
.build();
|
||||
StructOrError<RouteAction> struct1 = RouteAction.fromEnvoyProtoRouteAction(proto1);
|
||||
assertThat(struct1.getErrorDetail()).isNull();
|
||||
assertThat(struct1.getStruct().getTimeoutNano())
|
||||
.isEqualTo(TimeUnit.SECONDS.toNanos(15L)); // default value
|
||||
assertThat(struct1.getStruct().getCluster()).isEqualTo("cluster-foo");
|
||||
assertThat(struct1.getStruct().getWeightedCluster()).isNull();
|
||||
|
||||
// cluster_specifier = cluster_header
|
||||
// cluster_specifier = cluster, infinity timeout
|
||||
io.envoyproxy.envoy.config.route.v3.RouteAction proto2 =
|
||||
io.envoyproxy.envoy.config.route.v3.RouteAction.newBuilder()
|
||||
.setMaxGrpcTimeout(Durations.fromNanos(0))
|
||||
.setTimeout(Durations.fromMicros(20L))
|
||||
.setCluster("cluster-foo")
|
||||
.build();
|
||||
StructOrError<RouteAction> struct2 = RouteAction.fromEnvoyProtoRouteAction(proto2);
|
||||
assertThat(struct2.getStruct().getTimeoutNano())
|
||||
.isEqualTo(Long.MAX_VALUE); // infinite
|
||||
|
||||
// cluster_specifier = cluster, infinity timeout
|
||||
io.envoyproxy.envoy.config.route.v3.RouteAction proto3 =
|
||||
io.envoyproxy.envoy.config.route.v3.RouteAction.newBuilder()
|
||||
.setTimeout(Durations.fromNanos(0))
|
||||
.setCluster("cluster-foo")
|
||||
.build();
|
||||
StructOrError<RouteAction> struct3 = RouteAction.fromEnvoyProtoRouteAction(proto3);
|
||||
assertThat(struct3.getStruct().getTimeoutNano()).isEqualTo(Long.MAX_VALUE); // infinite
|
||||
|
||||
// cluster_specifier = cluster_header
|
||||
io.envoyproxy.envoy.config.route.v3.RouteAction proto4 =
|
||||
io.envoyproxy.envoy.config.route.v3.RouteAction.newBuilder()
|
||||
.setClusterHeader("cluster-bar")
|
||||
.build();
|
||||
StructOrError<RouteAction> struct2 = RouteAction.fromEnvoyProtoRouteAction(proto2);
|
||||
assertThat(struct2).isNull();
|
||||
StructOrError<RouteAction> struct4 = RouteAction.fromEnvoyProtoRouteAction(proto4);
|
||||
assertThat(struct4).isNull();
|
||||
|
||||
// cluster_specifier = weighted_cluster
|
||||
io.envoyproxy.envoy.config.route.v3.RouteAction proto3 =
|
||||
io.envoyproxy.envoy.config.route.v3.RouteAction proto5 =
|
||||
io.envoyproxy.envoy.config.route.v3.RouteAction.newBuilder()
|
||||
.setMaxGrpcTimeout(Durations.fromSeconds(6L))
|
||||
.setTimeout(Durations.fromMicros(20L))
|
||||
.setWeightedClusters(
|
||||
WeightedCluster.newBuilder()
|
||||
.addClusters(
|
||||
|
|
@ -422,10 +448,12 @@ public class EnvoyProtoDataTest {
|
|||
.setName("cluster-baz")
|
||||
.setWeight(UInt32Value.newBuilder().setValue(100))))
|
||||
.build();
|
||||
StructOrError<RouteAction> struct3 = RouteAction.fromEnvoyProtoRouteAction(proto3);
|
||||
assertThat(struct3.getErrorDetail()).isNull();
|
||||
assertThat(struct3.getStruct().getCluster()).isNull();
|
||||
assertThat(struct3.getStruct().getWeightedCluster())
|
||||
StructOrError<RouteAction> struct5 = RouteAction.fromEnvoyProtoRouteAction(proto5);
|
||||
assertThat(struct5.getErrorDetail()).isNull();
|
||||
assertThat(struct5.getStruct().getTimeoutNano())
|
||||
.isEqualTo(TimeUnit.SECONDS.toNanos(6L));
|
||||
assertThat(struct5.getStruct().getCluster()).isNull();
|
||||
assertThat(struct5.getStruct().getWeightedCluster())
|
||||
.containsExactly(new ClusterWeight("cluster-baz", 100));
|
||||
|
||||
// cluster_specifier unset
|
||||
|
|
|
|||
|
|
@ -750,7 +750,8 @@ public class XdsClientImplTest {
|
|||
new io.grpc.xds.RouteMatch(
|
||||
/* prefix= */ null,
|
||||
/* path= */ "/service1/method1"),
|
||||
new EnvoyProtoData.RouteAction("cl1.googleapis.com", null)));
|
||||
new EnvoyProtoData.RouteAction(
|
||||
TimeUnit.SECONDS.toNanos(15L), "cl1.googleapis.com", null)));
|
||||
assertThat(routes.get(1)).isEqualTo(
|
||||
new EnvoyProtoData.Route(
|
||||
// path match with weighted cluster route
|
||||
|
|
@ -758,6 +759,7 @@ public class XdsClientImplTest {
|
|||
/* prefix= */ null,
|
||||
/* path= */ "/service2/method2"),
|
||||
new EnvoyProtoData.RouteAction(
|
||||
TimeUnit.SECONDS.toNanos(15L),
|
||||
null,
|
||||
ImmutableList.of(
|
||||
new EnvoyProtoData.ClusterWeight("cl21.googleapis.com", 30),
|
||||
|
|
@ -769,7 +771,8 @@ public class XdsClientImplTest {
|
|||
new io.grpc.xds.RouteMatch(
|
||||
/* prefix= */ "/service1/",
|
||||
/* path= */ null),
|
||||
new EnvoyProtoData.RouteAction("cl1.googleapis.com", null)));
|
||||
new EnvoyProtoData.RouteAction(
|
||||
TimeUnit.SECONDS.toNanos(15L), "cl1.googleapis.com", null)));
|
||||
assertThat(routes.get(3)).isEqualTo(
|
||||
new EnvoyProtoData.Route(
|
||||
// default match with cluster route
|
||||
|
|
@ -777,7 +780,7 @@ public class XdsClientImplTest {
|
|||
/* prefix= */ "",
|
||||
/* path= */ null),
|
||||
new EnvoyProtoData.RouteAction(
|
||||
"cluster.googleapis.com", null)));
|
||||
TimeUnit.SECONDS.toNanos(15L), "cluster.googleapis.com", null)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ public class XdsNameResolverTest {
|
|||
new RouteMatch(
|
||||
new PathMatcher(null, "", null), Collections.<HeaderMatcher>emptyList(),
|
||||
new FractionMatcher(10, 20)),
|
||||
new RouteAction("cluster-foo", null));
|
||||
new RouteAction(15L, "cluster-foo", null));
|
||||
Route r2 =
|
||||
new Route(
|
||||
new RouteMatch(
|
||||
|
|
@ -92,6 +92,7 @@ public class XdsNameResolverTest {
|
|||
new HeaderMatcher(":scheme", "https", null, null, null, null, null, false)),
|
||||
null),
|
||||
new RouteAction(
|
||||
15L,
|
||||
null,
|
||||
Arrays.asList(
|
||||
new ClusterWeight("cluster-foo", 20),
|
||||
|
|
@ -134,7 +135,7 @@ public class XdsNameResolverTest {
|
|||
new RouteMatch(
|
||||
new PathMatcher("/service/method", null, null),
|
||||
Collections.<HeaderMatcher>emptyList(), null),
|
||||
new RouteAction("cluster-foo", null));
|
||||
new RouteAction(15L, "cluster-foo", null));
|
||||
|
||||
Map<String, ?> config =
|
||||
XdsNameResolver.generateXdsRoutingRawConfig(Arrays.asList(route, route));
|
||||
|
|
|
|||
Loading…
Reference in New Issue