Skip to content

Commit 49c14d2

Browse files
committed
Generate service config with method config containing timeout configuration that falls back to LDS's http protocol option max stream duration.
1 parent baaba74 commit 49c14d2

File tree

2 files changed

+80
-33
lines changed

2 files changed

+80
-33
lines changed

xds/src/main/java/io/grpc/xds/XdsNameResolver.java

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ final class XdsNameResolver extends NameResolver {
8686
private final ConcurrentMap<String, AtomicInteger> clusterRefs = new ConcurrentHashMap<>();
8787
private final ConfigSelector configSelector = new ConfigSelector();
8888

89-
private volatile List<Route> currentRoutes = Collections.emptyList();
89+
private volatile RoutingConfig routingConfig = RoutingConfig.empty;
9090
private Listener2 listener;
9191
private ObjectPool<XdsClient> xdsClientPool;
9292
private XdsClient xdsClient;
@@ -326,7 +326,7 @@ public Result selectConfig(PickSubchannelArgs args) {
326326
String cluster = null;
327327
Route selectedRoute = null;
328328
do {
329-
for (Route route : currentRoutes) {
329+
for (Route route : routingConfig.routes) {
330330
if (route.getRouteMatch().matches(
331331
"/" + args.getMethodDescriptor().getFullMethodName(), asciiHeaders)) {
332332
selectedRoute = route;
@@ -359,8 +359,13 @@ public Result selectConfig(PickSubchannelArgs args) {
359359
// TODO(chengyuanzhang): avoid service config generation and parsing for each call.
360360
Map<String, ?> rawServiceConfig = Collections.emptyMap();
361361
if (enableTimeout) {
362-
rawServiceConfig = generateServiceConfigWithMethodTimeoutConfig(
363-
selectedRoute.getRouteAction().getTimeoutNano());
362+
long timeoutNano = selectedRoute.getRouteAction().getTimeoutNano();
363+
if (timeoutNano == 0) {
364+
timeoutNano = routingConfig.fallbackTimeoutNano;
365+
}
366+
if (timeoutNano > 0) {
367+
rawServiceConfig = generateServiceConfigWithMethodTimeoutConfig(timeoutNano);
368+
}
364369
}
365370
ConfigOrError parsedServiceConfig = serviceConfigParser.parseServiceConfig(rawServiceConfig);
366371
Object config = parsedServiceConfig.getConfig();
@@ -430,10 +435,12 @@ private class ResolveState implements LdsResourceWatcher {
430435
private String rdsResource;
431436
@Nullable
432437
private RdsResourceWatcher rdsWatcher;
438+
private long httpMaxStreamDurationNano;
433439

434440
@Override
435441
public void onChanged(LdsUpdate update) {
436442
logger.log(XdsLogLevel.INFO, "Receive LDS resource update: {0}", update);
443+
httpMaxStreamDurationNano = update.getHttpMaxStreamDurationNano();
437444
List<VirtualHost> virtualHosts = update.getVirtualHosts();
438445
String rdsName = update.getRdsName();
439446
if (rdsName != null && rdsName.equals(rdsResource)) {
@@ -479,6 +486,8 @@ private void stop() {
479486
private void updateRoutes(List<VirtualHost> virtualHosts) {
480487
VirtualHost virtualHost = findVirtualHostForHostName(virtualHosts, authority);
481488
if (virtualHost == null) {
489+
logger.log(XdsLogLevel.WARNING,
490+
"Failed to find virtual host matching hostname {0}", authority);
482491
listener.onResult(emptyResult);
483492
return;
484493
}
@@ -515,7 +524,7 @@ private void updateRoutes(List<VirtualHost> virtualHosts) {
515524
}
516525
// Make newly added clusters selectable by config selector and deleted clusters no longer
517526
// selectable.
518-
currentRoutes = routes;
527+
routingConfig = new RoutingConfig(httpMaxStreamDurationNano, routes);
519528
shouldUpdateResult = false;
520529
for (String cluster : deletedClusters) {
521530
int count = clusterRefs.get(cluster).decrementAndGet();
@@ -560,4 +569,19 @@ public void onResourceDoesNotExist(String resourceName) {
560569
}
561570
}
562571
}
572+
573+
/**
574+
* Grouping of the list of usable routes and their corresponding fallback timeout value.
575+
*/
576+
private static class RoutingConfig {
577+
private long fallbackTimeoutNano;
578+
private List<Route> routes;
579+
580+
private static RoutingConfig empty = new RoutingConfig(0L, Collections.<Route>emptyList());
581+
582+
private RoutingConfig(long fallbackTimeoutNano, List<Route> routes) {
583+
this.fallbackTimeoutNano = fallbackTimeoutNano;
584+
this.routes = routes;
585+
}
586+
}
563587
}

xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ public void resolving_encounterErrorLdsAndRdsWatchers() {
264264
public void resolving_matchingVirtualHostNotFoundInLdsResource() {
265265
resolver.start(mockListener);
266266
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
267-
xdsClient.deliverVirtualHostsViaLds(AUTHORITY, buildUnmatchedVirtualHosts());
267+
xdsClient.deliverLdsUpdate(AUTHORITY, 0L, buildUnmatchedVirtualHosts());
268268
assertEmptyResolutionResult();
269269
}
270270

@@ -275,7 +275,7 @@ public void resolving_matchingVirtualHostNotFoundInRdsResource() {
275275
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
276276
xdsClient.deliverRdsName(AUTHORITY, rdsResource);
277277
assertThat(xdsClient.rdsWatcher).isNotNull();
278-
xdsClient.deliverVirtualHostsViaRds(rdsResource, buildUnmatchedVirtualHosts());
278+
xdsClient.deliverRdsUpdate(rdsResource, buildUnmatchedVirtualHosts());
279279
assertEmptyResolutionResult();
280280
}
281281

@@ -291,6 +291,43 @@ private List<VirtualHost> buildUnmatchedVirtualHosts() {
291291
Collections.singletonList(route2)));
292292
}
293293

294+
@SuppressWarnings("unchecked")
295+
@Test
296+
public void resolved_noTimeout() {
297+
resolver.start(mockListener);
298+
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
299+
Route route = new Route(new RouteMatch(null, call1.getFullMethodNameForPath()),
300+
new RouteAction(0L, cluster1, null)); // per-route timeout unset
301+
VirtualHost virtualHost = new VirtualHost("does not matter",
302+
Collections.singletonList(AUTHORITY), Collections.singletonList(route));
303+
xdsClient.deliverLdsUpdate(AUTHORITY, 0L, Collections.singletonList(virtualHost));
304+
verify(mockListener).onResult(resolutionResultCaptor.capture());
305+
ResolutionResult result = resolutionResultCaptor.getValue();
306+
InternalConfigSelector configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
307+
Result selectResult = configSelector.selectConfig(
308+
new PickSubchannelArgsImpl(call1.methodDescriptor, new Metadata(), CallOptions.DEFAULT));
309+
assertThat(selectResult.getStatus().isOk()).isTrue();
310+
assertThat(selectResult.getCallOptions().getOption(XdsNameResolver.CLUSTER_SELECTION_KEY))
311+
.isEqualTo(cluster1);
312+
assertThat((Map<String, ?>) selectResult.getConfig()).isEmpty();
313+
}
314+
315+
@Test
316+
public void resolved_fallbackToHttpMaxStreamDurationAsTimeout() {
317+
resolver.start(mockListener);
318+
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
319+
Route route = new Route(new RouteMatch(null, call1.getFullMethodNameForPath()),
320+
new RouteAction(0L, cluster1, null)); // per-route timeout unset
321+
VirtualHost virtualHost = new VirtualHost("does not matter",
322+
Collections.singletonList(AUTHORITY), Collections.singletonList(route));
323+
xdsClient.deliverLdsUpdate(AUTHORITY, TimeUnit.SECONDS.toNanos(5L),
324+
Collections.singletonList(virtualHost));
325+
verify(mockListener).onResult(resolutionResultCaptor.capture());
326+
ResolutionResult result = resolutionResultCaptor.getValue();
327+
InternalConfigSelector configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
328+
assertCallSelectResult(call1, configSelector, cluster1, 5.0);
329+
}
330+
294331
@Test
295332
public void resolved_simpleCallSucceeds() {
296333
InternalConfigSelector configSelector = resolveToClusters();
@@ -320,7 +357,7 @@ public void resolved_resourceUpdateAfterCallStarted() {
320357

321358
reset(mockListener);
322359
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
323-
xdsClient.deliverRoutesViaLds(
360+
xdsClient.deliverLdsUpdate(
324361
AUTHORITY,
325362
Arrays.asList(
326363
new Route(
@@ -355,7 +392,7 @@ public void resolved_resourceUpdatedBeforeCallStarted() {
355392
InternalConfigSelector configSelector = resolveToClusters();
356393
reset(mockListener);
357394
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
358-
xdsClient.deliverRoutesViaLds(
395+
xdsClient.deliverLdsUpdate(
359396
AUTHORITY,
360397
Arrays.asList(
361398
new Route(
@@ -386,7 +423,7 @@ public void resolved_raceBetweenCallAndRepeatedResourceUpdate() {
386423

387424
reset(mockListener);
388425
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
389-
xdsClient.deliverRoutesViaLds(
426+
xdsClient.deliverLdsUpdate(
390427
AUTHORITY,
391428
Arrays.asList(
392429
new Route(
@@ -402,7 +439,7 @@ public void resolved_raceBetweenCallAndRepeatedResourceUpdate() {
402439
Arrays.asList(cluster1, cluster2, "another-cluster"),
403440
(Map<String, ?>) result.getServiceConfig().getConfig());
404441

405-
xdsClient.deliverRoutesViaLds(
442+
xdsClient.deliverLdsUpdate(
406443
AUTHORITY,
407444
Arrays.asList(
408445
new Route(
@@ -420,13 +457,13 @@ public void resolved_raceBetweenClusterReleasedAndResourceUpdateAddBackAgain() {
420457
InternalConfigSelector configSelector = resolveToClusters();
421458
Result result = assertCallSelectResult(call1, configSelector, cluster1, 15.0);
422459
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
423-
xdsClient.deliverRoutesViaLds(
460+
xdsClient.deliverLdsUpdate(
424461
AUTHORITY,
425462
Collections.singletonList(
426463
new Route(
427464
new RouteMatch(null, call2.getFullMethodNameForPath()),
428465
new RouteAction(TimeUnit.SECONDS.toNanos(15L), cluster2, null))));
429-
xdsClient.deliverRoutesViaLds(
466+
xdsClient.deliverLdsUpdate(
430467
AUTHORITY,
431468
Arrays.asList(
432469
new Route(
@@ -445,7 +482,7 @@ public void resolved_simpleCallSucceeds_routeToWeightedCluster() {
445482
when(mockRandom.nextInt(anyInt())).thenReturn(90, 10);
446483
resolver.start(mockListener);
447484
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
448-
xdsClient.deliverRoutesViaLds(
485+
xdsClient.deliverLdsUpdate(
449486
AUTHORITY,
450487
Arrays.asList(
451488
new Route(
@@ -501,7 +538,7 @@ private static Result assertCallSelectResult(
501538
private InternalConfigSelector resolveToClusters() {
502539
resolver.start(mockListener);
503540
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
504-
xdsClient.deliverRoutesViaLds(
541+
xdsClient.deliverLdsUpdate(
505542
AUTHORITY,
506543
Arrays.asList(
507544
new Route(
@@ -761,7 +798,7 @@ void shutdown() {
761798
// no-op
762799
}
763800

764-
void deliverVirtualHostsViaLds(final String resourceName,
801+
void deliverLdsUpdate(final String resourceName, final long httpMaxStreamDurationNano,
765802
final List<VirtualHost> virtualHosts) {
766803
syncContext.execute(new Runnable() {
767804
@Override
@@ -770,6 +807,7 @@ public void run() {
770807
return;
771808
}
772809
LdsUpdate.Builder updateBuilder = LdsUpdate.newBuilder();
810+
updateBuilder.setHttpMaxStreamDurationNano(httpMaxStreamDurationNano);
773811
for (VirtualHost virtualHost : virtualHosts) {
774812
updateBuilder.addVirtualHost(virtualHost);
775813
}
@@ -778,7 +816,7 @@ public void run() {
778816
});
779817
}
780818

781-
void deliverRoutesViaLds(final String resourceName, final List<Route> routes) {
819+
void deliverLdsUpdate(final String resourceName, final List<Route> routes) {
782820
syncContext.execute(new Runnable() {
783821
@Override
784822
public void run() {
@@ -816,8 +854,7 @@ public void run() {
816854
});
817855
}
818856

819-
void deliverVirtualHostsViaRds(final String resourceName,
820-
final List<VirtualHost> virtualHosts) {
857+
void deliverRdsUpdate(final String resourceName, final List<VirtualHost> virtualHosts) {
821858
syncContext.execute(new Runnable() {
822859
@Override
823860
public void run() {
@@ -829,20 +866,6 @@ public void run() {
829866
});
830867
}
831868

832-
void deliverRoutesViaRds(final String resourceName, final List<Route> routes) {
833-
syncContext.execute(new Runnable() {
834-
@Override
835-
public void run() {
836-
if (!resourceName.equals(rdsResource)) {
837-
return;
838-
}
839-
VirtualHost virtualHost =
840-
new VirtualHost("virtual-host", Collections.singletonList(AUTHORITY), routes);
841-
rdsWatcher.onChanged(RdsUpdate.fromVirtualHosts(Collections.singletonList(virtualHost)));
842-
}
843-
});
844-
}
845-
846869
void deliverRdsResourceNotFound(final String resourceName) {
847870
syncContext.execute(new Runnable() {
848871
@Override

0 commit comments

Comments
 (0)