Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions A117-ring-hash-exit-idle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
A117: Ring Hash Exit Idle Behavior Changes
----
* Author(s): dfawley@
* Approver(s): markdroth@, ejona@
* Implemented in:
* Last updated: 2026-05-15
* Discussion at: https://groups.google.com/g/grpc-io/c/ByCPdvi5lrQ

## Abstract

Update the Ring Hash LB policy to create connections when explictly requested by
the channel to do so, instead of ignoring the request.

## Background

The Ring Hash LB policy, as defined in [gRFC A42][A42], does not create
connections upon creation. Even though it is not specified, all implementations
of gRPC also ignored calls to the "exit idle" / "request connection" method.

It has been observed that this behavior can cause problems, however.
Specifically, when using the gRPC [connectivity API][], if an application
requests a channel using ring hash to connect, but ring hash ignores the
incoming request from the channel, the application will never see a change to
the state of the channel. Further, if this channel's connectivity state is used
to compute the health of a server using that channel, that can cause serious
problems, as an unhealthy server will not receive the traffic it needs to make
ring hash connect.

### Related Proposals:

* [gRFC A42: xDS Ring Hash LB Policy][A42]
* [gRFC A76: Improvements to the Ring Hash LB Policy][A76]
* [gRFC A61: IPv4 and IPv6 Dualstack Backend Support][A61rh]

## Proposal

This proposal makes two behavior changes:

1. Ring Hash should enter the CONNECTING state if it is currently in the IDLE
state and the channel requests it to exit idle mode, instead of ignoring the
request.

This will cause the eager-connection logic described in [gRFC A61][A61rh] to
trigger:

> when the aggregated connectivity state is either TRANSIENT_FAILURE or
> CONNECTING, the ring_hash policy proactively triggers connection attempts
> across all of the subchannels, even without seeing any picks.

2. New connection attempts not triggered by an RPC should begin with a random
endpoint, ignoring endpoint weights. This is a behavior change from [gRFC
A61][A61rh]'s TRANSIENT_FAILURE / CONNECTING behavior, which currently states
the choice of endpoints is up to the implementation:

> It does not matter which IDLE endpoint is chosen; that is left up to the
> implementation to determine.

Using a randomized endpoint will ensure that load is distributed evenly
Comment thread
ejona86 marked this conversation as resolved.
across available backends if many individual clients are instructed to
connect at the same time.

### Temporary environment variable protection

Even though this is a behavior change, as the behavior is triggered by the
application, this feature does not need to be protected by a standardized
environment variable. Individual langauge implementations may wish to provide
their language-specific mechanism to revert the behavior change temporarily in
the event that issues are encountered by users.

## Rationale

Another option is to change nothing in the Ring Hash policy and require users to
consider "IDLE" as a "healthy" state in their application. This is still
surprising / unintuitive behavior, and it would be too hard to communicate this
to all users.

## Implementation

The implementation should be done in all languages that support Ring Hash.


[A42]: A42-xds-ring-hash-lb-policy.md
[A76]: A76-ring-hash-improvements.md
[A61rh]: A61-IPv4-IPv6-dualstack-backends.md#ring-hash
[connectivity API]: https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md
3 changes: 2 additions & 1 deletion A42-xds-ring-hash-lb-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ A42: xDS Ring Hash LB Policy
* Implemented in: Java (C-core and Go in progress)
* Last updated: 2021-06-04
* Discussion at: https://groups.google.com/g/grpc-io/c/_Z_oiWVXf6k
* Updated by: [A61: IPv4 and IPv6 Dualstack Backend Support](A61-IPv4-IPv6-dualstack-backends.md)
* Updated by: [A61: IPv4 and IPv6 Dualstack Backend Support](A61-IPv4-IPv6-dualstack-backends.md), [A76: Improvements to the Ring Hash LB Policy](A76-ring-hash-improvements.md), and [A117: Ring Hash Exit Idle Behavior Changes](A117-ring-hash-exit-idle.md)


## Abstract

Expand Down
11 changes: 8 additions & 3 deletions A61-IPv4-IPv6-dualstack-backends.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ A61: IPv4 and IPv6 Dualstack Backend Support
* Implemented in: C-core
* Last updated: 2025-03-06
* Discussion at: https://groups.google.com/g/grpc-io/c/VjORlKP97cE/m/ihqyN32TAQAJ
* Updated by: [A76: Improvements to the Ring Hash LB Policy](A76-ring-hash-improvements.md) and [A117: Ring Hash Exit Idle Behavior Changes][A117]

## Abstract

Expand Down Expand Up @@ -43,7 +44,7 @@ addresses per endpoint in xDS. We will support the new xDS APIs being
added for that effort as well. Note that this change has implications
for session affinity behavior in xDS.

### Related Proposals:
### Related Proposals:
* [Support for dual stack EDS endpoints in Envoy][envoy-design]
* [gRFC A17: Client-Side Health Checking][A17]
* [gRFC A27: xDS-Based Global Load Balancing][A27]
Expand Down Expand Up @@ -596,10 +597,13 @@ if the aggregated connectivity state is TRANSIENT_FAILURE or CONNECTING
and there are no endpoints in CONNECTING state, the ring_hash policy will
choose one of the endpoints in IDLE state (if any) to trigger a connection
attempt on. It does not matter which IDLE endpoint is chosen; that is
left up to the implementation to determine. One possible implementation
of this is shown in the following pseudo-code:
left up to the implementation to determine. (Update: gRFC [A117][] now
specifies a _random_ endpoint should be chosen.) One possible implementation of
this is shown in the following pseudo-code:

```
# Updated to show a randomized starting location per gRFC A117.
endpoints = shuffle(endpoints);
if (aggregated_state_is_connecting_or_transient_failure) {
first_idle_index = -1;
for (i = 0; i < endpoints.size(); ++i) {
Expand Down Expand Up @@ -961,3 +965,4 @@ N/A
[RFC-8305]: https://www.rfc-editor.org/rfc/rfc8305
[A62]: A62-pick-first.md
[backoff-spec]: https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md
[A117]: A117-ring-hash-exit-idle.md