@@ -336,11 +336,47 @@ public void get_throttledAndRecover() throws Exception {
336336 // let it pass throttler
337337 fakeThrottler .nextResult = false ;
338338 fakeClock .forwardTime (10 , TimeUnit .MILLISECONDS );
339- // Backoff entry evicted from cache.
340- verify (evictionListener )
341- .onEviction (eq (routeLookupRequest ), any (CacheEntry .class ), eq (EvictionType .EXPLICIT ));
342339 // Assert that Rls LB policy picker was updated.
343340 assertThat (fakeHelper .lastPicker .toString ()).isEqualTo ("RlsPicker{target=service1}" );
341+ // Backoff entry present but marked as not active anymore in cache, so next rpc should not be
342+ // backed off.
343+ resp = getInSyncContext (routeLookupRequest );
344+ assertThat (resp .isPending ()).isTrue ();
345+ }
346+
347+ @ Test
348+ public void get_throttled_backoffBehavior () throws Exception {
349+ setUpRlsLbClient ();
350+ RouteLookupRequest routeLookupRequest = RouteLookupRequest .create (ImmutableMap .of (
351+ "server" , "bigtable.googleapis.com" , "service-key" , "foo" , "method-key" , "bar" ));
352+ rlsServerImpl .setLookupTable (
353+ ImmutableMap .of (
354+ routeLookupRequest ,
355+ RouteLookupResponse .create (ImmutableList .of ("target" ), "header" )));
356+
357+ fakeThrottler .nextResult = true ;
358+ fakeBackoffProvider .nextPolicy = createBackoffPolicy (10 , TimeUnit .MILLISECONDS );
359+
360+ CachedRouteLookupResponse resp = getInSyncContext (routeLookupRequest );
361+ assertThat (resp .hasError ()).isTrue ();
362+
363+ // let it be throttled again
364+ fakeClock .forwardTime (10 , TimeUnit .MILLISECONDS );
365+ resp = getInSyncContext (routeLookupRequest );
366+ assertThat (resp .hasError ()).isTrue ();
367+
368+ // Assert that the backoff policy is still in effect for the cache entry.
369+ fakeClock .forwardTime (9 , TimeUnit .MILLISECONDS );
370+ resp = getInSyncContext (routeLookupRequest );
371+ assertThat (resp .hasError ()).isTrue ();
372+
373+ fakeClock .forwardTime (1 , TimeUnit .MILLISECONDS );
374+ // Assert that Rls LB policy picker was updated.
375+ assertThat (fakeHelper .lastPicker .toString ()).isEqualTo ("RlsPicker{target=service1}" );
376+ // Backoff entry marked as not active anymore in cache, so next rpc should not be backed off.
377+ fakeThrottler .nextResult = false ;
378+ resp = getInSyncContext (routeLookupRequest );
379+ assertThat (resp .isPending ()).isTrue ();
344380 }
345381
346382 @ Test
@@ -360,19 +396,6 @@ public void run() {
360396 };
361397 fakeHelper .oobChannel .notifyWhenStateChanged (fakeHelper .oobChannel .getState (false ),
362398 channelStateListener );
363- RouteLookupRequest routeLookupRequest = RouteLookupRequest .create (ImmutableMap .of (
364- "server" , "bigtable.googleapis.com" , "service-key" , "foo" , "method-key" , "bar" ));
365- rlsServerImpl .setLookupTable (
366- ImmutableMap .of (
367- routeLookupRequest ,
368- RouteLookupResponse .create (ImmutableList .of ("target" ), "header" )));
369-
370- CachedRouteLookupResponse resp = getInSyncContext (routeLookupRequest );
371- assertThat (resp .isPending ()).isTrue ();
372- // server response
373- fakeClock .forwardTime (SERVER_LATENCY_MILLIS , TimeUnit .MILLISECONDS );
374- resp = getInSyncContext (routeLookupRequest );
375- assertThat (resp .hasData ()).isTrue ();
376399
377400 fakeHelper .server .shutdown ();
378401 // Channel goes to IDLE state from the shutdown listener handling.
@@ -383,22 +406,19 @@ public void run() {
383406 } catch (InterruptedException e ) {
384407 fakeHelper .server .shutdownNow ();
385408 }
386- // Use a different key to cause a cache miss and trigger a RPC.
387- RouteLookupRequest routeLookupRequest2 = RouteLookupRequest .create (ImmutableMap .of (
388- "server" , "bigtable.googleapis.com" , "service-key" , "foo2" , "method-key" , "bar" ));
389- // Rls channel will go to TRANSIENT_FAILURE (back-off) because the picker notices the
390- // subchannel state IDLE and the server transport listener is null.
391- resp = getInSyncContext (routeLookupRequest2 );
409+ RouteLookupRequest routeLookupRequest = RouteLookupRequest .create (ImmutableMap .of (
410+ "server" , "bigtable.googleapis.com" , "service-key" , "foo" , "method-key" , "bar" ));
411+ // Rls channel will go to TRANSIENT_FAILURE (connection back-off).
412+ CachedRouteLookupResponse resp = getInSyncContext (routeLookupRequest );
392413 assertThat (resp .isPending ()).isTrue ();
393414 assertThat (rlsChannelState [0 ]).isEqualTo (ConnectivityState .TRANSIENT_FAILURE );
394415 // Throttle the next rpc call.
395416 fakeThrottler .nextResult = true ;
396417 fakeBackoffProvider .nextPolicy = createBackoffPolicy (10 , TimeUnit .MILLISECONDS );
397418
398- // Cause another cache miss by using a new request key. This will create a back-off Rls
399- // cache entry.
419+ // Cause a cache miss by using a new request key. This will create a back-off Rls cache entry.
400420 RouteLookupRequest routeLookupRequest3 = RouteLookupRequest .create (ImmutableMap .of (
401- "server" , "bigtable.googleapis.com" , "service-key" , "foo3 " , "method-key" , "bar" ));
421+ "server" , "bigtable.googleapis.com" , "service-key" , "foo2 " , "method-key" , "bar" ));
402422 resp = getInSyncContext (routeLookupRequest3 );
403423
404424 assertThat (resp .hasError ()).isTrue ();
@@ -413,9 +433,6 @@ public void run() {
413433 SharedResourcePool .forResource (GrpcUtil .SHARED_CHANNEL_EXECUTOR );
414434 AtomicBoolean isSuccess = new AtomicBoolean (false );
415435 ((ExecutorService ) defaultExecutorPool .getObject ()).submit (() -> {
416- // Backoff entry evicted from cache.
417- verify (evictionListener )
418- .onEviction (eq (routeLookupRequest3 ), any (CacheEntry .class ), eq (EvictionType .EXPLICIT ));
419436 // Assert that Rls LB policy picker was updated.
420437 assertThat (fakeHelper .lastPicker .toString ()).isEqualTo ("RlsPicker{target=service1}" );
421438 isSuccess .set (true );
0 commit comments