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

grpc / grpc-java / #20233

02 Apr 2026 12:18PM UTC coverage: 88.792% (+0.008%) from 88.784%
#20233

push

github

web-flow
[xds] Implement A114: WRR support for custom backend metrics (#12645)

### Description
This PR implements [gRFC A114: WRR Support for Custom Backend
Metrics](https://github.com/grpc/proposal/pull/536).

It updates the `weighted_round_robin` policy to allow users to configure
which backend metrics drive the load balancing weights.

### Key Changes
* **Configuration**: Supports the new
`metric_names_for_computing_utilization` field in
`WeightedRoundRobinLbConfig`.
* **Weight Calculation**: Implements logic to resolve custom metrics
(including map lookups like `named_metrics.foo`) when
`application_utilization` is absent.
* **Refactor**: Centralizes the complex metric lookup and validation
logic (checking for NaN, <= 0, etc.) into a new internal utility
`MetricReportUtils`.
* **Testing**: Verifies correct precedence: `application_utilization` >
`custom_metrics` (max valid value) > `cpu_utilization`.

36007 of 40552 relevant lines covered (88.79%)

0.89 hits per line

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

89.19
/../xds/src/main/java/io/grpc/xds/WeightedRoundRobinLoadBalancerProvider.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.xds;
18

19
import com.google.common.annotations.VisibleForTesting;
20
import io.grpc.Deadline;
21
import io.grpc.Internal;
22
import io.grpc.LoadBalancer;
23
import io.grpc.LoadBalancer.Helper;
24
import io.grpc.LoadBalancerProvider;
25
import io.grpc.NameResolver.ConfigOrError;
26
import io.grpc.Status;
27
import io.grpc.internal.GrpcUtil;
28
import io.grpc.internal.JsonUtil;
29
import io.grpc.xds.WeightedRoundRobinLoadBalancer.WeightedRoundRobinLoadBalancerConfig;
30
import java.util.List;
31
import java.util.Map;
32

33
/**
34
 * Provides a {@link WeightedRoundRobinLoadBalancer}.
35
 * */
36
@Internal
37
public final class WeightedRoundRobinLoadBalancerProvider extends LoadBalancerProvider {
1✔
38

39
  @VisibleForTesting
40
  static final long MIN_WEIGHT_UPDATE_PERIOD_NANOS = 100_000_000L; // 100ms
41

42
  static final String SCHEME = "weighted_round_robin";
43

44
  @Override
45
  public LoadBalancer newLoadBalancer(Helper helper) {
46
    return new WeightedRoundRobinLoadBalancer(helper, Deadline.getSystemTicker());
1✔
47
  }
48

49
  @Override
50
  public boolean isAvailable() {
51
    return true;
1✔
52
  }
53

54
  @Override
55
  public int getPriority() {
56
    return 5;
1✔
57
  }
58

59
  @Override
60
  public String getPolicyName() {
61
    return SCHEME;
1✔
62
  }
63

64
  @Override
65
  public ConfigOrError parseLoadBalancingPolicyConfig(Map<String, ?> rawConfig) {
66
    try {
67
      return parseLoadBalancingPolicyConfigInternal(rawConfig);
1✔
68
    } catch (RuntimeException e) {
×
69
      return ConfigOrError.fromError(
×
70
          Status.UNAVAILABLE.withCause(e).withDescription(
×
71
              "Failed parsing configuration for " + getPolicyName()));
×
72
    }
73
  }
74

75
  private ConfigOrError parseLoadBalancingPolicyConfigInternal(Map<String, ?> rawConfig) {
76
    Long blackoutPeriodNanos = JsonUtil.getStringAsDuration(rawConfig, "blackoutPeriod");
1✔
77
    Long weightExpirationPeriodNanos =
1✔
78
        JsonUtil.getStringAsDuration(rawConfig, "weightExpirationPeriod");
1✔
79
    Long oobReportingPeriodNanos = JsonUtil.getStringAsDuration(rawConfig, "oobReportingPeriod");
1✔
80
    Boolean enableOobLoadReport = JsonUtil.getBoolean(rawConfig, "enableOobLoadReport");
1✔
81
    Long weightUpdatePeriodNanos = JsonUtil.getStringAsDuration(rawConfig, "weightUpdatePeriod");
1✔
82
    Float errorUtilizationPenalty = JsonUtil.getNumberAsFloat(rawConfig, "errorUtilizationPenalty");
1✔
83
    List<String> metricNamesForComputingUtilization = JsonUtil.getListOfStrings(rawConfig,
1✔
84
        LoadBalancerConfigFactory.METRIC_NAMES_FOR_COMPUTING_UTILIZATION);
85

86
    WeightedRoundRobinLoadBalancerConfig.Builder configBuilder =
87
        WeightedRoundRobinLoadBalancerConfig.newBuilder();
1✔
88
    if (blackoutPeriodNanos != null) {
1✔
89
      configBuilder.setBlackoutPeriodNanos(blackoutPeriodNanos);
1✔
90
    }
91
    if (weightExpirationPeriodNanos != null) {
1✔
92
      configBuilder.setWeightExpirationPeriodNanos(weightExpirationPeriodNanos);
1✔
93
    }
94
    if (enableOobLoadReport != null) {
1✔
95
      configBuilder.setEnableOobLoadReport(enableOobLoadReport);
1✔
96
    }
97
    if (oobReportingPeriodNanos != null) {
1✔
98
      configBuilder.setOobReportingPeriodNanos(oobReportingPeriodNanos);
1✔
99
    }
100
    if (weightUpdatePeriodNanos != null) {
1✔
101
      configBuilder.setWeightUpdatePeriodNanos(weightUpdatePeriodNanos);
1✔
102
      if (weightUpdatePeriodNanos < MIN_WEIGHT_UPDATE_PERIOD_NANOS) {
1✔
103
        configBuilder.setWeightUpdatePeriodNanos(MIN_WEIGHT_UPDATE_PERIOD_NANOS);
1✔
104
      }
105
    }
106
    if (errorUtilizationPenalty != null) {
1✔
107
      configBuilder.setErrorUtilizationPenalty(errorUtilizationPenalty);
1✔
108
    }
109
    if (metricNamesForComputingUtilization != null
1✔
110
        && GrpcUtil.getFlag("GRPC_EXPERIMENTAL_WRR_CUSTOM_METRICS", false)) {
1✔
111
      configBuilder.setMetricNamesForComputingUtilization(metricNamesForComputingUtilization);
1✔
112
    }
113
    return ConfigOrError.fromConfig(configBuilder.build());
1✔
114
  }
115
}
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

© 2026 Coveralls, Inc