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

grpc / grpc-java / #19157

08 Apr 2024 06:30PM CUT coverage: 88.312%. Remained the same
#19157

push

github

web-flow
buildscripts: Migrate PSM Interop to Artifact Registry (#11079) (#11092)

From Container Registry (gcr.io) to Artifact Registry (pkg.dev).

30337 of 34352 relevant lines covered (88.31%)

0.88 hits per line

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

94.12
/../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.Attributes;
21
import io.grpc.NameResolver;
22
import io.grpc.Status;
23
import io.grpc.SynchronizationContext;
24

25
/**
26
 * This wrapper class can add retry capability to any polling {@link NameResolver} implementation
27
 * that supports calling {@link ResolutionResultListener}s with the outcome of each resolution.
28
 *
29
 * <p>The {@link NameResolver} used with this
30
 */
31
final class RetryingNameResolver extends ForwardingNameResolver {
32

33
  private final NameResolver retriedNameResolver;
34
  private final RetryScheduler retryScheduler;
35
  private final SynchronizationContext syncContext;
36

37
  static final Attributes.Key<ResolutionResultListener> RESOLUTION_RESULT_LISTENER_KEY
1✔
38
      = Attributes.Key.create(
1✔
39
          "io.grpc.internal.RetryingNameResolver.RESOLUTION_RESULT_LISTENER_KEY");
40

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

55
  @Override
56
  public void start(Listener2 listener) {
57
    super.start(new RetryingListener(listener));
1✔
58
  }
1✔
59

60
  @Override
61
  public void shutdown() {
62
    super.shutdown();
1✔
63
    retryScheduler.reset();
1✔
64
  }
1✔
65

66
  /**
67
   * Used to get the underlying {@link NameResolver} that is getting its failed attempts retried.
68
   */
69
  @VisibleForTesting
70
  NameResolver getRetriedNameResolver() {
71
    return retriedNameResolver;
1✔
72
  }
73

74
  @VisibleForTesting
75
  class DelayedNameResolverRefresh implements Runnable {
1✔
76
    @Override
77
    public void run() {
78
      refresh();
×
79
    }
×
80
  }
81

82
  private class RetryingListener extends Listener2 {
83
    private Listener2 delegateListener;
84

85
    RetryingListener(Listener2 delegateListener) {
1✔
86
      this.delegateListener = delegateListener;
1✔
87
    }
1✔
88

89
    @Override
90
    public void onResult(ResolutionResult resolutionResult) {
91
      // If the resolution result listener is already an attribute it indicates that a name resolver
92
      // has already been wrapped with this class. This indicates a misconfiguration.
93
      if (resolutionResult.getAttributes().get(RESOLUTION_RESULT_LISTENER_KEY) != null) {
1✔
94
        throw new IllegalStateException(
1✔
95
            "RetryingNameResolver can only be used once to wrap a NameResolver");
96
      }
97

98
      delegateListener.onResult(resolutionResult.toBuilder().setAttributes(
1✔
99
              resolutionResult.getAttributes().toBuilder()
1✔
100
                  .set(RESOLUTION_RESULT_LISTENER_KEY, new ResolutionResultListener()).build())
1✔
101
          .build());
1✔
102
    }
1✔
103

104
    @Override
105
    public void onError(Status error) {
106
      delegateListener.onError(error);
1✔
107
      syncContext.execute(() -> retryScheduler.schedule(new DelayedNameResolverRefresh()));
1✔
108
    }
1✔
109
  }
110

111
  /**
112
   * Simple callback class to store in {@link ResolutionResult} attributes so that
113
   * ManagedChannel can indicate if the resolved addresses were accepted. Temporary until
114
   * the Listener2.onResult() API can be changed to return a boolean for this purpose.
115
   */
116
  class ResolutionResultListener {
1✔
117
    public void resolutionAttempted(boolean successful) {
118
      if (successful) {
1✔
119
        retryScheduler.reset();
1✔
120
      } else {
121
        retryScheduler.schedule(new DelayedNameResolverRefresh());
1✔
122
      }
123
    }
1✔
124
  }
125
}
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