mirror of https://github.com/grpc/grpc-java.git
core: add prepareToLoseNetwork() method to ManagedChannel
This commit is contained in:
parent
77397b9dd0
commit
6ee6eae5a0
|
|
@ -119,6 +119,24 @@ public abstract class ManagedChannel extends Channel {
|
|||
*
|
||||
* @since 1.8.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/4056")
|
||||
public void resetConnectBackoff() {}
|
||||
|
||||
/**
|
||||
* Invoking this method moves the channel into the IDLE state and triggers tear-down of the
|
||||
* channel's name resolver and load balancer, while still allowing on-going RPCs on the channel to
|
||||
* continue. New RPCs on the channel will trigger creation of a new connection.
|
||||
*
|
||||
* <p>This is primarily intended for Android users when a device is transitioning from a cellular
|
||||
* to a wifi connection. Initially the device will maintain both the cellular and wifi
|
||||
* connections, but the OS also issues a notification that after a short time the cellular
|
||||
* connection will be terminated. Apps may invoke this method to ensure that new RPCs are created
|
||||
* using the wifi connection, rather than the soon-to-be-disconnected cellular network.
|
||||
*
|
||||
* <p>No-op if not supported by implementation.
|
||||
*
|
||||
* @since 1.11.0
|
||||
*/
|
||||
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/4056")
|
||||
public void prepareToLoseNetwork() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,19 +310,7 @@ public final class ManagedChannelImpl extends ManagedChannel implements Instrume
|
|||
// could cancel the timer.
|
||||
return;
|
||||
}
|
||||
logger.log(Level.FINE, "[{0}] Entering idle mode", getLogId());
|
||||
// nameResolver and loadBalancer are guaranteed to be non-null. If any of them were null,
|
||||
// either the idleModeTimer ran twice without exiting the idle mode, or the task in shutdown()
|
||||
// did not cancel idleModeTimer, both of which are bugs.
|
||||
nameResolver.shutdown();
|
||||
nameResolverStarted = false;
|
||||
nameResolver = getNameResolver(target, nameResolverFactory, nameResolverParams);
|
||||
lbHelper.lb.shutdown();
|
||||
lbHelper = null;
|
||||
subchannelPicker = null;
|
||||
if (!channelStateManager.isDisabled()) {
|
||||
channelStateManager.gotoState(IDLE);
|
||||
}
|
||||
enterIdleMode();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -368,6 +356,24 @@ public final class ManagedChannelImpl extends ManagedChannel implements Instrume
|
|||
}
|
||||
}
|
||||
|
||||
// Must be run from channelExecutor
|
||||
private void enterIdleMode() {
|
||||
logger.log(Level.FINE, "[{0}] Entering idle mode", getLogId());
|
||||
// nameResolver and loadBalancer are guaranteed to be non-null. If any of them were null,
|
||||
// either the idleModeTimer ran twice without exiting the idle mode, or the task in shutdown()
|
||||
// did not cancel idleModeTimer, or prepareToLoseNetwork() ran while shutdown or in idle, all of
|
||||
// which are bugs.
|
||||
nameResolver.shutdown();
|
||||
nameResolverStarted = false;
|
||||
nameResolver = getNameResolver(target, nameResolverFactory, nameResolverParams);
|
||||
lbHelper.lb.shutdown();
|
||||
lbHelper = null;
|
||||
subchannelPicker = null;
|
||||
if (!channelStateManager.isDisabled()) {
|
||||
channelStateManager.gotoState(IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
// Must be run from channelExecutor
|
||||
private void cancelIdleTimer() {
|
||||
if (idleModeTimerFuture != null) {
|
||||
|
|
@ -760,6 +766,22 @@ public final class ManagedChannelImpl extends ManagedChannel implements Instrume
|
|||
}).drain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareToLoseNetwork() {
|
||||
class PrepareToLoseNetworkRunnable implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
if (shutdown.get() || lbHelper == null) {
|
||||
return;
|
||||
}
|
||||
cancelIdleTimer();
|
||||
enterIdleMode();
|
||||
}
|
||||
}
|
||||
|
||||
channelExecutor.executeLater(new PrepareToLoseNetworkRunnable()).drain();
|
||||
}
|
||||
|
||||
/**
|
||||
* A registry that prevents channel shutdown from killing existing retry attempts that are in
|
||||
* backoff.
|
||||
|
|
|
|||
|
|
@ -1507,6 +1507,31 @@ public class ManagedChannelImplTest {
|
|||
assertEquals(CONNECTING, channel.getState(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prepareToLoseNetworkEntersIdle() {
|
||||
createChannel(new FakeNameResolverFactory(true), NO_INTERCEPTOR);
|
||||
helper.updateBalancingState(READY, mockPicker);
|
||||
assertEquals(READY, channel.getState(false));
|
||||
|
||||
channel.prepareToLoseNetwork();
|
||||
|
||||
assertEquals(IDLE, channel.getState(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prepareToLoseNetworkAfterIdleTimerIsNoOp() {
|
||||
long idleTimeoutMillis = 2000L;
|
||||
createChannel(
|
||||
new FakeNameResolverFactory(true), NO_INTERCEPTOR, true /* request connection*/,
|
||||
idleTimeoutMillis);
|
||||
timer.forwardNanos(TimeUnit.MILLISECONDS.toNanos(idleTimeoutMillis));
|
||||
assertEquals(IDLE, channel.getState(false));
|
||||
|
||||
channel.prepareToLoseNetwork();
|
||||
|
||||
assertEquals(IDLE, channel.getState(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBalancingStateDoesUpdatePicker() {
|
||||
ClientStream mockStream = mock(ClientStream.class);
|
||||
|
|
|
|||
Loading…
Reference in New Issue