-
Notifications
You must be signed in to change notification settings - Fork 4.7k
balancer: expose endpoint weight and hostname as experimental APIs #9074
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 4 commits
5ed3447
d39465e
83417df
1b58d32
0132067
3b06903
cad2a5f
9fa484c
777e7f6
f30c259
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| /* | ||
| * | ||
| * Copyright 2026 gRPC authors. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| * | ||
| */ | ||
|
|
||
| // Package hostname contains utilities for the endpoint hostname attribute | ||
| // (used for per-endpoint :authority / SNI override). | ||
| // | ||
| // # Experimental | ||
| // | ||
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | ||
| // later release. | ||
|
Comment on lines
+24
to
+25
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please indicate in the note that all APIs in this package are experimental here. That way, every single API does not have to carry that same warning. |
||
| package hostname | ||
|
|
||
| import "google.golang.org/grpc/resolver" | ||
|
|
||
| type hostnameKey struct{} | ||
|
|
||
| // Set returns a copy of the given endpoint with the hostname attribute set. | ||
| // If hostname is empty the endpoint is returned unmodified. | ||
| // | ||
| // # Experimental | ||
| // | ||
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | ||
| // later release. | ||
| func Set(endpoint resolver.Endpoint, hostname string) resolver.Endpoint { | ||
| if hostname == "" { | ||
| return endpoint | ||
| } | ||
| endpoint.Attributes = endpoint.Attributes.WithValue(hostnameKey{}, hostname) | ||
| return endpoint | ||
| } | ||
|
|
||
| // Hostname returns the hostname attribute of endpoint. If this attribute is | ||
| // not set, it returns the empty string. | ||
| // | ||
| // # Experimental | ||
| // | ||
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | ||
| // later release. | ||
| func Hostname(endpoint resolver.Endpoint) string { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it will be better to rename it as
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| h, _ := endpoint.Attributes.Value(hostnameKey{}).(string) | ||
| return h | ||
| } | ||
|
|
||
| // FromAddress returns the hostname attribute from a legacy | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't need to export the function to retrieve hostname from
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| // resolver.Address. It checks both the modern Attributes field and the | ||
| // deprecated BalancerAttributes field for compatibility. | ||
| // | ||
| // # Experimental | ||
| // | ||
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | ||
| // later release. | ||
| func FromAddress(addr resolver.Address) string { | ||
| if h, ok := addr.Attributes.Value(hostnameKey{}).(string); ok && h != "" { | ||
| return h | ||
| } | ||
| h, _ := addr.BalancerAttributes.Value(hostnameKey{}).(string) | ||
| return h | ||
| } | ||
|
Comment on lines
+59
to
+69
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Most LB policies should not need access to attributes stores in a |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| /* | ||
| * | ||
| * Copyright 2026 gRPC authors. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| * | ||
| */ | ||
|
|
||
| package hostname_test | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "google.golang.org/grpc/balancer/hostname" | ||
| "google.golang.org/grpc/resolver" | ||
| ) | ||
|
|
||
| func TestHostname_SetAndGet(t *testing.T) { | ||
|
Pranjali-2501 marked this conversation as resolved.
Outdated
|
||
| ep := resolver.Endpoint{} | ||
| if h := hostname.Hostname(ep); h != "" { | ||
| t.Errorf("empty = %q", h) | ||
| } | ||
|
|
||
| ep2 := hostname.Set(ep, "myservice.example.com") | ||
| if h := hostname.Hostname(ep2); h != "myservice.example.com" { | ||
| t.Errorf("got %q", h) | ||
| } | ||
|
|
||
| // empty hostname returns same endpoint | ||
| ep3 := hostname.Set(ep2, "") | ||
| if hostname.Hostname(ep3) != "myservice.example.com" { | ||
| t.Error("empty should not overwrite") | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,17 +29,18 @@ import ( | |
| "time" | ||
|
|
||
| "github.com/google/go-cmp/cmp" | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove this new line.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| "google.golang.org/grpc" | ||
| "google.golang.org/grpc/backoff" | ||
| "google.golang.org/grpc/balancer" | ||
| pfbalancer "google.golang.org/grpc/balancer/pickfirst" | ||
| pfinternal "google.golang.org/grpc/balancer/pickfirst/internal" | ||
| "google.golang.org/grpc/balancer/weight" | ||
| "google.golang.org/grpc/codes" | ||
| "google.golang.org/grpc/connectivity" | ||
| "google.golang.org/grpc/credentials/insecure" | ||
| "google.golang.org/grpc/internal" | ||
| "google.golang.org/grpc/internal/balancer/stub" | ||
| "google.golang.org/grpc/internal/balancer/weight" | ||
| "google.golang.org/grpc/internal/channelz" | ||
| "google.golang.org/grpc/internal/envconfig" | ||
| "google.golang.org/grpc/internal/grpcsync" | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. Please move this to a directory inside of the top-level experimental directory. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| /* | ||
| * | ||
| * Copyright 2026 gRPC authors. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| * | ||
| */ | ||
|
|
||
| // Package weight contains utilities to manage endpoint weights. Weights are | ||
| // used by LB policies such as ringhash to distribute load across multiple | ||
| // endpoints. | ||
| // | ||
| // # Experimental | ||
| // | ||
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | ||
| // later release. | ||
|
Comment on lines
+25
to
+26
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as the other comment. Please mention that all APIs in this package are experimental here, and ignore the warnings on every single API. |
||
| package weight | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "google.golang.org/grpc/resolver" | ||
| ) | ||
|
|
||
| // attributeKey is the type used as the key to store EndpointInfo in the | ||
| // Attributes field of resolver.Endpoint. | ||
| type attributeKey struct{} | ||
|
|
||
| // EndpointInfo will be stored in the Attributes field of Endpoints in order to | ||
| // use the ringhash balancer. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment needs to be updated, since this is no longer only pertinent to the ring_hash LB policy. |
||
| type EndpointInfo struct { | ||
| Weight uint32 | ||
| } | ||
|
|
||
| // Equal allows the values to be compared by Attributes.Equal. | ||
| func (a EndpointInfo) Equal(o any) bool { | ||
| oa, ok := o.(EndpointInfo) | ||
| return ok && oa.Weight == a.Weight | ||
| } | ||
|
|
||
| // Set returns a copy of endpoint in which the Attributes field is updated with | ||
| // EndpointInfo. | ||
| // | ||
| // # Experimental | ||
| // | ||
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | ||
| // later release. | ||
| func Set(endpoint resolver.Endpoint, epInfo EndpointInfo) resolver.Endpoint { | ||
| endpoint.Attributes = endpoint.Attributes.WithValue(attributeKey{}, epInfo) | ||
| return endpoint | ||
| } | ||
|
|
||
| // String returns a human-readable representation of EndpointInfo. | ||
| // This method is intended for logging, testing, and debugging purposes only. | ||
| // Do not rely on the output format, as it is not guaranteed to remain stable. | ||
| func (a EndpointInfo) String() string { | ||
| return fmt.Sprintf("Weight: %d", a.Weight) | ||
| } | ||
|
Comment on lines
63
to
68
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There doesn't seem to be any calls to this method. Let's get rid of this. |
||
|
|
||
| // FromEndpoint returns the EndpointInfo stored in the Attributes field of an | ||
| // endpoint. It returns an empty EndpointInfo if attribute is not found. | ||
| // | ||
| // # Experimental | ||
| // | ||
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | ||
| // later release. | ||
| func FromEndpoint(endpoint resolver.Endpoint) EndpointInfo { | ||
| v := endpoint.Attributes.Value(attributeKey{}) | ||
| ei, _ := v.(EndpointInfo) | ||
| return ei | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| /* | ||
| * | ||
| * Copyright 2026 gRPC authors. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| * | ||
| */ | ||
|
|
||
| package weight_test | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/google/go-cmp/cmp" | ||
|
|
||
| "google.golang.org/grpc/attributes" | ||
| "google.golang.org/grpc/balancer/weight" | ||
| "google.golang.org/grpc/internal/grpctest" | ||
| "google.golang.org/grpc/resolver" | ||
| ) | ||
|
|
||
| type s struct { | ||
| grpctest.Tester | ||
| } | ||
|
|
||
| func Test(t *testing.T) { | ||
| grpctest.RunSubTests(t, s{}) | ||
| } | ||
|
|
||
| func (s) TestEndpointInfoToAndFromAttributes(t *testing.T) { | ||
| tests := []struct { | ||
| desc string | ||
| inputEndpointInfo weight.EndpointInfo | ||
| inputAttributes *attributes.Attributes | ||
| wantEndpointInfo weight.EndpointInfo | ||
| }{ | ||
| { | ||
| desc: "empty_attributes", | ||
| inputEndpointInfo: weight.EndpointInfo{Weight: 100}, | ||
| inputAttributes: nil, | ||
| wantEndpointInfo: weight.EndpointInfo{Weight: 100}, | ||
| }, | ||
| { | ||
| desc: "non-empty_attributes", | ||
| inputEndpointInfo: weight.EndpointInfo{Weight: 100}, | ||
| inputAttributes: attributes.New("foo", "bar"), | ||
| wantEndpointInfo: weight.EndpointInfo{Weight: 100}, | ||
| }, | ||
| { | ||
| desc: "endpointInfo_not_present_in_empty_attributes", | ||
| inputEndpointInfo: weight.EndpointInfo{}, | ||
| inputAttributes: nil, | ||
| wantEndpointInfo: weight.EndpointInfo{}, | ||
| }, | ||
| { | ||
| desc: "endpointInfo_not_present_in_non-empty_attributes", | ||
| inputEndpointInfo: weight.EndpointInfo{}, | ||
| inputAttributes: attributes.New("foo", "bar"), | ||
| wantEndpointInfo: weight.EndpointInfo{}, | ||
| }, | ||
| } | ||
|
|
||
| for _, test := range tests { | ||
| t.Run(test.desc, func(t *testing.T) { | ||
| endpoint := resolver.Endpoint{Attributes: test.inputAttributes} | ||
| endpoint = weight.Set(endpoint, test.inputEndpointInfo) | ||
| gotEndpointInfo := weight.FromEndpoint(endpoint) | ||
| if !cmp.Equal(gotEndpointInfo, test.wantEndpointInfo) { | ||
| t.Errorf("gotEndpointInfo: %v, wantEndpointInfo: %v", gotEndpointInfo, test.wantEndpointInfo) | ||
| } | ||
|
|
||
| }) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,8 @@ | |
| // Package weight contains utilities to manage endpoint weights. Weights are | ||
| // used by LB policies such as ringhash to distribute load across multiple | ||
| // endpoints. | ||
| // | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of putting a deprecated message and creating new files in
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done - i also added the "Experimental" comment because this is a newly-public API. is that fine? |
||
| // Deprecated: use google.golang.org/grpc/balancer/weight instead. | ||
| package weight | ||
|
|
||
| import ( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,12 +16,14 @@ | |
| * | ||
| */ | ||
|
|
||
| // Deprecated: use google.golang.org/grpc/balancer/weight instead. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above, use
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| package weight_test | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/google/go-cmp/cmp" | ||
|
|
||
| "google.golang.org/grpc/attributes" | ||
| "google.golang.org/grpc/internal/balancer/weight" | ||
| "google.golang.org/grpc/internal/grpctest" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,12 +27,13 @@ import ( | |
| "time" | ||
|
|
||
| "github.com/google/go-cmp/cmp" | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove this newline.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| "google.golang.org/grpc/attributes" | ||
| "google.golang.org/grpc/balancer" | ||
| "google.golang.org/grpc/balancer/pickfirst" | ||
| "google.golang.org/grpc/balancer/ringhash" | ||
| "google.golang.org/grpc/balancer/roundrobin" | ||
| "google.golang.org/grpc/internal/balancer/weight" | ||
| "google.golang.org/grpc/balancer/weight" | ||
| "google.golang.org/grpc/internal/envconfig" | ||
| "google.golang.org/grpc/internal/hierarchy" | ||
| iringhash "google.golang.org/grpc/internal/ringhash" | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move this to
experimental/balancer/hostnamepackage. We are trying to house all newly added experimental APIs to the top-levelexperimentaldirectory.