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
|
* @since 1.8.0
|
||||||
*/
|
*/
|
||||||
@ExperimentalApi
|
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/4056")
|
||||||
public void resetConnectBackoff() {}
|
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.
|
// could cancel the timer.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.log(Level.FINE, "[{0}] Entering idle mode", getLogId());
|
enterIdleMode();
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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
|
// Must be run from channelExecutor
|
||||||
private void cancelIdleTimer() {
|
private void cancelIdleTimer() {
|
||||||
if (idleModeTimerFuture != null) {
|
if (idleModeTimerFuture != null) {
|
||||||
|
|
@ -760,6 +766,22 @@ public final class ManagedChannelImpl extends ManagedChannel implements Instrume
|
||||||
}).drain();
|
}).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
|
* A registry that prevents channel shutdown from killing existing retry attempts that are in
|
||||||
* backoff.
|
* backoff.
|
||||||
|
|
|
||||||
|
|
@ -1507,6 +1507,31 @@ public class ManagedChannelImplTest {
|
||||||
assertEquals(CONNECTING, channel.getState(false));
|
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
|
@Test
|
||||||
public void updateBalancingStateDoesUpdatePicker() {
|
public void updateBalancingStateDoesUpdatePicker() {
|
||||||
ClientStream mockStream = mock(ClientStream.class);
|
ClientStream mockStream = mock(ClientStream.class);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue