netty: refactor NettyChannelBuilder keepalive API (#2874)

To be in line with `NettyServerBuilder` APIs
- Deprecated `enableKeepAlive(boolean enable)` and
`enableKeepAlive(boolean enable, long keepAliveDelay, TimeUnit delayUnit, long keepAliveTimeout, 
TimeUnit timeoutUnit)`
which never worked in v1.2

- Added `keepAliveTime(long keepAliveTime, TimeUnit timeUnit)` and
`keepAliveTimeout(long keepAliveTimeout, TimeUnit timeUnit)`
This commit is contained in:
ZHANG Dapeng 2017-04-04 18:19:41 -07:00 committed by GitHub
parent 90788305a3
commit 1c1864be73
5 changed files with 95 additions and 46 deletions

View File

@ -176,26 +176,25 @@ public final class GrpcUtil {
/**
* The default timeout in nanos for a keepalive ping request.
*/
public static final long DEFAULT_KEEPALIVE_TIMEOUT_NANOS = TimeUnit.MINUTES.toNanos(2);
public static final long DEFAULT_KEEPALIVE_TIMEOUT_NANOS = TimeUnit.SECONDS.toNanos(20L);
/**
* The magic keepalive time value that disables client keepalive.
*/
public static final long KEEPALIVE_TIME_NANOS_DISABLED = Long.MAX_VALUE;
/**
* The default delay in nanos for server keepalive.
*
* @since 1.3.0
*/
public static final long DEFAULT_SERVER_KEEPALIVE_TIME_NANOS = TimeUnit.HOURS.toNanos(2L);
/**
* The default timeout in nanos for a server keepalive ping request.
*
* @since 1.3.0
*/
public static final long DEFAULT_SERVER_KEEPALIVE_TIMEOUT_NANOS = TimeUnit.SECONDS.toNanos(20L);
/**
* The magic keepalive time value that disables keepalive.
*
* @since 1.3.0
*/
public static final long SERVER_KEEPALIVE_TIME_NANOS_DISABLED = Long.MAX_VALUE;

View File

@ -36,6 +36,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static io.grpc.internal.GrpcUtil.DEFAULT_KEEPALIVE_DELAY_NANOS;
import static io.grpc.internal.GrpcUtil.DEFAULT_KEEPALIVE_TIMEOUT_NANOS;
import static io.grpc.internal.GrpcUtil.KEEPALIVE_TIME_NANOS_DISABLED;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
@ -71,6 +72,9 @@ public final class NettyChannelBuilder
extends AbstractManagedChannelImplBuilder<NettyChannelBuilder> {
public static final int DEFAULT_FLOW_CONTROL_WINDOW = 1048576; // 1MiB
private static final long MIN_KEEPALIVE_TIMEOUT_NANO = TimeUnit.MICROSECONDS.toNanos(499L);
private static final long AS_LARGE_AS_INFINITE = TimeUnit.DAYS.toNanos(1000L);
private final Map<ChannelOption<?>, Object> channelOptions =
new HashMap<ChannelOption<?>, Object>();
@ -83,9 +87,8 @@ public final class NettyChannelBuilder
private SslContext sslContext;
private int flowControlWindow = DEFAULT_FLOW_CONTROL_WINDOW;
private int maxHeaderListSize = GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE;
private boolean enableKeepAlive;
private long keepAliveDelayNanos;
private long keepAliveTimeoutNanos;
private long keepAliveTimeNanos = KEEPALIVE_TIME_NANOS_DISABLED;
private long keepAliveTimeoutNanos = DEFAULT_KEEPALIVE_TIMEOUT_NANOS;
private TransportCreationParamsFilterFactory dynamicParamsFactory;
/**
@ -241,28 +244,63 @@ public final class NettyChannelBuilder
return this;
}
/**
* Enable keepalive with default delay and timeout.
*
* @deprecated Please use {@link #keepAliveTime} and {@link #keepAliveTimeout} instead
*/
@Deprecated
public final NettyChannelBuilder enableKeepAlive(boolean enable) {
enableKeepAlive = enable;
if (enable) {
keepAliveDelayNanos = DEFAULT_KEEPALIVE_DELAY_NANOS;
keepAliveTimeoutNanos = DEFAULT_KEEPALIVE_TIMEOUT_NANOS;
return keepAliveTime(DEFAULT_KEEPALIVE_DELAY_NANOS, TimeUnit.NANOSECONDS);
}
return keepAliveTime(KEEPALIVE_TIME_NANOS_DISABLED, TimeUnit.NANOSECONDS);
}
/**
* Enable keepalive with custom delay and timeout.
*
* @deprecated Please use {@link #keepAliveTime} and {@link #keepAliveTimeout} instead
*/
@Deprecated
public final NettyChannelBuilder enableKeepAlive(boolean enable, long keepAliveDelay,
TimeUnit delayUnit, long keepAliveTimeout, TimeUnit timeoutUnit) {
if (enable) {
return keepAliveTime(keepAliveDelay, delayUnit)
.keepAliveTimeout(keepAliveTimeout, timeoutUnit);
}
return keepAliveTime(KEEPALIVE_TIME_NANOS_DISABLED, TimeUnit.NANOSECONDS);
}
/**
* Sets a custom keepalive time, the delay time for sending next keepalive ping. An unreasonably
* small value might be increased, and {@code Long.MAX_VALUE} nano seconds or an unreasonably
* large value will disable keepalive.
*
* @since 1.3.0
*/
public NettyChannelBuilder keepAliveTime(long keepAliveTime, TimeUnit timeUnit) {
checkArgument(keepAliveTime > 0L, "keepalive time must be positive");
keepAliveTimeNanos = timeUnit.toNanos(keepAliveTime);
if (keepAliveTimeNanos >= AS_LARGE_AS_INFINITE) {
// Bump keepalive time to infinite. This disables keepalive.
keepAliveTimeNanos = KEEPALIVE_TIME_NANOS_DISABLED;
}
return this;
}
/**
* Enable keepalive with custom delay and timeout.
* Sets a custom keepalive timeout, the timeout for keepalive ping requests. An unreasonably small
* value might be increased.
*
* @since 1.3.0
*/
public final NettyChannelBuilder enableKeepAlive(boolean enable, long keepAliveDelay,
TimeUnit delayUnit, long keepAliveTimeout, TimeUnit timeoutUnit) {
enableKeepAlive = enable;
if (enable) {
keepAliveDelayNanos = delayUnit.toNanos(keepAliveDelay);
keepAliveTimeoutNanos = timeoutUnit.toNanos(keepAliveTimeout);
public NettyChannelBuilder keepAliveTimeout(long keepAliveTimeout, TimeUnit timeUnit) {
checkArgument(keepAliveTimeout > 0L, "keepalive timeout must be positive");
keepAliveTimeoutNanos = timeUnit.toNanos(keepAliveTimeout);
if (keepAliveTimeoutNanos < MIN_KEEPALIVE_TIMEOUT_NANO) {
// Bump keepalive timeout.
keepAliveTimeoutNanos = MIN_KEEPALIVE_TIMEOUT_NANO;
}
return this;
}
@ -272,7 +310,7 @@ public final class NettyChannelBuilder
protected ClientTransportFactory buildTransportFactory() {
return new NettyTransportFactory(dynamicParamsFactory, channelType, channelOptions,
negotiationType, sslContext, eventLoopGroup, flowControlWindow, maxInboundMessageSize(),
maxHeaderListSize, enableKeepAlive, keepAliveDelayNanos, keepAliveTimeoutNanos);
maxHeaderListSize, keepAliveTimeNanos, keepAliveTimeoutNanos);
}
@Override
@ -393,7 +431,6 @@ public final class NettyChannelBuilder
private final int flowControlWindow;
private final int maxMessageSize;
private final int maxHeaderListSize;
private final boolean enableKeepAlive;
private final long keepAliveDelayNanos;
private final long keepAliveTimeoutNanos;
@ -402,7 +439,7 @@ public final class NettyChannelBuilder
NettyTransportFactory(TransportCreationParamsFilterFactory transportCreationParamsFilterFactory,
Class<? extends Channel> channelType, Map<ChannelOption<?>, ?> channelOptions,
NegotiationType negotiationType, SslContext sslContext, EventLoopGroup group,
int flowControlWindow, int maxMessageSize, int maxHeaderListSize, boolean enableKeepAlive,
int flowControlWindow, int maxMessageSize, int maxHeaderListSize,
long keepAliveDelayNanos, long keepAliveTimeoutNanos) {
this.channelType = channelType;
this.negotiationType = negotiationType;
@ -423,7 +460,6 @@ public final class NettyChannelBuilder
this.flowControlWindow = flowControlWindow;
this.maxMessageSize = maxMessageSize;
this.maxHeaderListSize = maxHeaderListSize;
this.enableKeepAlive = enableKeepAlive;
this.keepAliveDelayNanos = keepAliveDelayNanos;
this.keepAliveTimeoutNanos = keepAliveTimeoutNanos;
usingSharedGroup = group == null;
@ -446,10 +482,8 @@ public final class NettyChannelBuilder
NettyClientTransport transport = new NettyClientTransport(
dparams.getTargetServerAddress(), channelType, channelOptions, group,
dparams.getProtocolNegotiator(), flowControlWindow,
maxMessageSize, maxHeaderListSize, dparams.getAuthority(), dparams.getUserAgent());
if (enableKeepAlive) {
transport.enableKeepAlive(true, keepAliveDelayNanos, keepAliveTimeoutNanos);
}
maxMessageSize, maxHeaderListSize, keepAliveDelayNanos, keepAliveTimeoutNanos,
dparams.getAuthority(), dparams.getUserAgent());
return transport;
}

View File

@ -31,6 +31,7 @@
package io.grpc.netty;
import static io.grpc.internal.GrpcUtil.KEEPALIVE_TIME_NANOS_DISABLED;
import static io.netty.channel.ChannelOption.SO_KEEPALIVE;
import com.google.common.annotations.VisibleForTesting;
@ -82,7 +83,6 @@ class NettyClientTransport implements ConnectionClientTransport {
private final int maxMessageSize;
private final int maxHeaderListSize;
private KeepAliveManager keepAliveManager;
private boolean enableKeepAlive;
private long keepAliveDelayNanos;
private long keepAliveTimeoutNanos;
@ -98,7 +98,8 @@ class NettyClientTransport implements ConnectionClientTransport {
SocketAddress address, Class<? extends Channel> channelType,
Map<ChannelOption<?>, ?> channelOptions, EventLoopGroup group,
ProtocolNegotiator negotiator, int flowControlWindow, int maxMessageSize,
int maxHeaderListSize, String authority, @Nullable String userAgent) {
int maxHeaderListSize, long keepAliveDelayNanos, long keepAliveTimeoutNanos,
String authority, @Nullable String userAgent) {
this.negotiator = Preconditions.checkNotNull(negotiator, "negotiator");
this.address = Preconditions.checkNotNull(address, "address");
this.group = Preconditions.checkNotNull(group, "group");
@ -107,17 +108,10 @@ class NettyClientTransport implements ConnectionClientTransport {
this.flowControlWindow = flowControlWindow;
this.maxMessageSize = maxMessageSize;
this.maxHeaderListSize = maxHeaderListSize;
this.authority = new AsciiString(authority);
this.userAgent = new AsciiString(GrpcUtil.getGrpcUserAgent("netty", userAgent));
}
/**
* Enable keepalive with custom delay and timeout.
*/
void enableKeepAlive(boolean enable, long keepAliveDelayNanos, long keepAliveTimeoutNanos) {
enableKeepAlive = enable;
this.keepAliveDelayNanos = keepAliveDelayNanos;
this.keepAliveTimeoutNanos = keepAliveTimeoutNanos;
this.authority = new AsciiString(authority);
this.userAgent = new AsciiString(GrpcUtil.getGrpcUserAgent("netty", userAgent));
}
@Override
@ -167,7 +161,7 @@ class NettyClientTransport implements ConnectionClientTransport {
lifecycleManager = new ClientTransportLifecycleManager(
Preconditions.checkNotNull(transportListener, "listener"));
EventLoop eventLoop = group.next();
if (enableKeepAlive) {
if (keepAliveDelayNanos != KEEPALIVE_TIME_NANOS_DISABLED) {
keepAliveManager = new KeepAliveManager(
new ClientKeepAlivePinger(this), eventLoop, keepAliveDelayNanos, keepAliveTimeoutNanos,
false);

View File

@ -40,6 +40,7 @@ import io.grpc.netty.ProtocolNegotiators.TlsNegotiator;
import io.netty.handler.ssl.SslContext;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLException;
import org.junit.Rule;
import org.junit.Test;
@ -164,4 +165,22 @@ public class NettyChannelBuilderTest {
assertEquals("bad_authority", n.getHost());
assertEquals(-1, n.getPort());
}
@Test
public void negativeKeepAliveTime() {
NettyChannelBuilder builder = NettyChannelBuilder.forTarget("fakeTarget");
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("keepalive time must be positive");
builder.keepAliveTime(-1L, TimeUnit.HOURS);
}
@Test
public void negativeKeepAliveTimeout() {
NettyChannelBuilder builder = NettyChannelBuilder.forTarget("fakeTarget");
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("keepalive timeout must be positive");
builder.keepAliveTimeout(-1L, TimeUnit.HOURS);
}
}

View File

@ -36,6 +36,7 @@ import static io.grpc.Status.Code.INTERNAL;
import static io.grpc.internal.GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;
import static io.grpc.internal.GrpcUtil.DEFAULT_SERVER_KEEPALIVE_TIMEOUT_NANOS;
import static io.grpc.internal.GrpcUtil.DEFAULT_SERVER_KEEPALIVE_TIME_NANOS;
import static io.grpc.internal.GrpcUtil.KEEPALIVE_TIME_NANOS_DISABLED;
import static io.grpc.internal.GrpcUtil.USER_AGENT_KEY;
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_WINDOW_SIZE;
import static org.junit.Assert.assertEquals;
@ -168,7 +169,7 @@ public class NettyClientTransportTest {
NettyClientTransport transport = new NettyClientTransport(
address, NioSocketChannel.class, channelOptions, group, newNegotiator(),
DEFAULT_WINDOW_SIZE, DEFAULT_MAX_MESSAGE_SIZE, GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE,
authority, null /* user agent */);
KEEPALIVE_TIME_NANOS_DISABLED, 1L, authority, null /* user agent */);
transports.add(transport);
callMeMaybe(transport.start(clientTransportListener));
@ -391,12 +392,14 @@ public class NettyClientTransportTest {
private NettyClientTransport newTransport(ProtocolNegotiator negotiator, int maxMsgSize,
int maxHeaderListSize, String userAgent, boolean enableKeepAlive) {
long keepAliveTimeNano = KEEPALIVE_TIME_NANOS_DISABLED;
if (enableKeepAlive) {
keepAliveTimeNano = 1000L;
}
NettyClientTransport transport = new NettyClientTransport(
address, NioSocketChannel.class, new HashMap<ChannelOption<?>, Object>(), group, negotiator,
DEFAULT_WINDOW_SIZE, maxMsgSize, maxHeaderListSize, authority, userAgent);
if (enableKeepAlive) {
transport.enableKeepAlive(true, 1000, 1000);
}
DEFAULT_WINDOW_SIZE, maxMsgSize, maxHeaderListSize, keepAliveTimeNano, 1L, authority,
userAgent);
transports.add(transport);
return transport;
}