-
Notifications
You must be signed in to change notification settings - Fork 4.6k
rls: only reset backoff on recovery from TRANSIENT_FAILURE #8720
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 1 commit
a6fcb7e
ca49ae7
c7eb618
943240d
ed5ab2c
2ad8249
faee5a0
5dcc02c
de73b31
1cf1ad8
2eb65c3
d044d4d
8a816be
af8497c
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 |
|---|---|---|
|
|
@@ -26,13 +26,15 @@ import ( | |
| "fmt" | ||
| "os" | ||
| "regexp" | ||
| "sync" | ||
| "testing" | ||
| "time" | ||
|
|
||
| "github.com/google/go-cmp/cmp" | ||
| "google.golang.org/grpc" | ||
| "google.golang.org/grpc/balancer" | ||
| "google.golang.org/grpc/codes" | ||
| "google.golang.org/grpc/connectivity" | ||
| "google.golang.org/grpc/credentials" | ||
| "google.golang.org/grpc/internal" | ||
| rlspb "google.golang.org/grpc/internal/proto/grpc_lookup_v1" | ||
|
|
@@ -463,3 +465,94 @@ func (s) TestNewControlChannelUnsupportedCredsBundle(t *testing.T) { | |
| t.Fatal("newControlChannel succeeded when expected to fail") | ||
| } | ||
| } | ||
|
|
||
| // TestControlChannelConnectivityStateTransitions verifies that the control | ||
| // channel only resets backoff when recovering from TRANSIENT_FAILURE, not | ||
| // when going through benign state changes like READY → IDLE → READY. | ||
| func (s) TestControlChannelConnectivityStateTransitions(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| states []connectivity.State | ||
| wantCallbackCount int | ||
| }{ | ||
| { | ||
| name: "READY → TRANSIENT_FAILURE → READY triggers callback", | ||
easwars marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| states: []connectivity.State{ | ||
| connectivity.TransientFailure, | ||
| connectivity.Ready, | ||
| }, | ||
| wantCallbackCount: 1, | ||
| }, | ||
| { | ||
| name: "READY → IDLE → READY does not trigger callback", | ||
| states: []connectivity.State{ | ||
| connectivity.Idle, | ||
| connectivity.Ready, | ||
| }, | ||
| wantCallbackCount: 0, | ||
| }, | ||
| { | ||
| name: "Multiple failures trigger callback each time", | ||
| states: []connectivity.State{ | ||
| connectivity.TransientFailure, | ||
| connectivity.Ready, | ||
| connectivity.TransientFailure, | ||
| connectivity.Ready, | ||
| }, | ||
| wantCallbackCount: 2, | ||
| }, | ||
| { | ||
| name: "IDLE between failures doesn't affect callback", | ||
| states: []connectivity.State{ | ||
| connectivity.TransientFailure, | ||
| connectivity.Idle, | ||
| connectivity.Ready, | ||
| }, | ||
| wantCallbackCount: 1, | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
|
||
| // Start an RLS server | ||
| rlsServer, _ := rlstest.SetupFakeRLSServer(t, nil) | ||
|
|
||
| // Setup callback to count invocations | ||
| callbackCount := 0 | ||
| var mu sync.Mutex | ||
| callback := func() { | ||
| mu.Lock() | ||
| callbackCount++ | ||
| mu.Unlock() | ||
| } | ||
|
|
||
| // Create control channel | ||
| ctrlCh, err := newControlChannel(rlsServer.Address, "", defaultTestTimeout, balancer.BuildOptions{}, callback) | ||
| if err != nil { | ||
| t.Fatalf("Failed to create control channel: %v", err) | ||
| } | ||
| defer ctrlCh.close() | ||
|
|
||
| // Give the channel time to reach initial READY state | ||
| time.Sleep(100 * time.Millisecond) | ||
|
|
||
| // Inject the test state sequence | ||
| for _, state := range tt.states { | ||
| ctrlCh.OnMessage(state) | ||
| // Give time for the monitoring goroutine to process the state | ||
| time.Sleep(50 * time.Millisecond) | ||
| } | ||
|
|
||
| // Give extra time for any pending callbacks | ||
| time.Sleep(100 * time.Millisecond) | ||
easwars marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| mu.Lock() | ||
| gotCallbackCount := callbackCount | ||
| mu.Unlock() | ||
|
|
||
| if gotCallbackCount != tt.wantCallbackCount { | ||
| t.Errorf("Got %d callback invocations, want %d", gotCallbackCount, tt.wantCallbackCount) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.