• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #19870

17 Jun 2025 10:14PM UTC coverage: 88.543% (-0.01%) from 88.556%
#19870

push

github

ejona86
xds: Add logical dns cluster support to XdsDepManager

ClusterResolverLb gets the NameResolverRegistry from
LoadBalancer.Helper, so a new API was added in NameResover.Args to
propagate the same object to the name resolver tree.

RetryingNameResolver was exposed to xds. This is expected to be
temporary, as the retrying is being removed from ManagedChannelImpl and
moved into the resolvers. At that point, DnsNameResolverProvider would
wrap DnsNameResolver with a similar API to RetryingNameResolver and xds
would no longer be responsible.

34637 of 39119 relevant lines covered (88.54%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.55
/../core/src/main/java/io/grpc/internal/RetryingNameResolver.java
1
/*
2
 * Copyright 2023 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.internal;
18

19
import com.google.common.annotations.VisibleForTesting;
20
import io.grpc.NameResolver;
21
import io.grpc.Status;
22
import io.grpc.SynchronizationContext;
23

24
/**
25
 * This wrapper class can add retry capability to any polling {@link NameResolver} implementation
26
 * that supports calling {@link ResolutionResultListener}s with the outcome of each resolution.
27
 *
28
 * <p>The {@link NameResolver} used with this
29
 */
30
public final class RetryingNameResolver extends ForwardingNameResolver {
31
  public static NameResolver wrap(NameResolver retriedNameResolver, Args args) {
32
    // For migration, this might become conditional
33
    return new RetryingNameResolver(
1✔
34
        retriedNameResolver,
35
        new BackoffPolicyRetryScheduler(
36
            new ExponentialBackoffPolicy.Provider(),
37
            args.getScheduledExecutorService(),
1✔
38
            args.getSynchronizationContext()),
1✔
39
        args.getSynchronizationContext());
1✔
40
  }
41

42
  private final NameResolver retriedNameResolver;
43
  private final RetryScheduler retryScheduler;
44
  private final SynchronizationContext syncContext;
45

46
  /**
47
   * Creates a new {@link RetryingNameResolver}.
48
   *
49
   * @param retriedNameResolver A {@link NameResolver} that will have failed attempt retried.
50
   * @param retryScheduler Used to schedule the retry attempts.
51
   */
52
  RetryingNameResolver(NameResolver retriedNameResolver, RetryScheduler retryScheduler,
53
      SynchronizationContext syncContext) {
54
    super(retriedNameResolver);
1✔
55
    this.retriedNameResolver = retriedNameResolver;
1✔
56
    this.retryScheduler = retryScheduler;
1✔
57
    this.syncContext = syncContext;
1✔
58
  }
1✔
59

60
  @Override
61
  public void start(Listener2 listener) {
62
    super.start(new RetryingListener(listener));
1✔
63
  }
1✔
64

65
  @Override
66
  public void shutdown() {
67
    super.shutdown();
1✔
68
    retryScheduler.reset();
1✔
69
  }
1✔
70

71
  /**
72
   * Used to get the underlying {@link NameResolver} that is getting its failed attempts retried.
73
   */
74
  @VisibleForTesting
75
  NameResolver getRetriedNameResolver() {
76
    return retriedNameResolver;
1✔
77
  }
78

79
  @VisibleForTesting
80
  class DelayedNameResolverRefresh implements Runnable {
1✔
81
    @Override
82
    public void run() {
83
      refresh();
×
84
    }
×
85
  }
86

87
  private class RetryingListener extends Listener2 {
88
    private Listener2 delegateListener;
89

90
    RetryingListener(Listener2 delegateListener) {
1✔
91
      this.delegateListener = delegateListener;
1✔
92
    }
1✔
93

94
    @Override
95
    public void onResult(ResolutionResult resolutionResult) {
96
      syncContext.execute(() -> onResult2(resolutionResult));
1✔
97
    }
1✔
98

99
    @Override
100
    public Status onResult2(ResolutionResult resolutionResult) {
101
      Status status = delegateListener.onResult2(resolutionResult);
1✔
102
      if (status.isOk()) {
1✔
103
        retryScheduler.reset();
1✔
104
      } else {
105
        retryScheduler.schedule(new DelayedNameResolverRefresh());
1✔
106
      }
107
      return status;
1✔
108
    }
109

110
    @Override
111
    public void onError(Status error) {
112
      delegateListener.onError(error);
1✔
113
      syncContext.execute(() -> retryScheduler.schedule(new DelayedNameResolverRefresh()));
1✔
114
    }
1✔
115
  }
116
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc