use of io.grpc.internal.KeepAliveManager.ClientKeepAlivePinger in project grpc-java by grpc.
the class NettyClientTransport method start.
@SuppressWarnings("unchecked")
@Override
public Runnable start(Listener transportListener) {
lifecycleManager = new ClientTransportLifecycleManager(Preconditions.checkNotNull(transportListener, "listener"));
EventLoop eventLoop = group.next();
if (keepAliveTimeNanos != KEEPALIVE_TIME_NANOS_DISABLED) {
keepAliveManager = new KeepAliveManager(new ClientKeepAlivePinger(this), eventLoop, keepAliveTimeNanos, keepAliveTimeoutNanos, keepAliveWithoutCalls);
}
handler = NettyClientHandler.newHandler(lifecycleManager, keepAliveManager, autoFlowControl, flowControlWindow, maxHeaderListSize, GrpcUtil.STOPWATCH_SUPPLIER, tooManyPingsRunnable, transportTracer, eagAttributes, authorityString, channelLogger);
ChannelHandler negotiationHandler = negotiator.newHandler(handler);
Bootstrap b = new Bootstrap();
b.option(ALLOCATOR, Utils.getByteBufAllocator(false));
b.group(eventLoop);
b.channelFactory(channelFactory);
// For non-socket based channel, the option will be ignored.
b.option(SO_KEEPALIVE, true);
// For non-epoll based channel, the option will be ignored.
if (keepAliveTimeNanos != KEEPALIVE_TIME_NANOS_DISABLED) {
ChannelOption<Integer> tcpUserTimeout = Utils.maybeGetTcpUserTimeoutOption();
if (tcpUserTimeout != null) {
b.option(tcpUserTimeout, (int) TimeUnit.NANOSECONDS.toMillis(keepAliveTimeoutNanos));
}
}
for (Map.Entry<ChannelOption<?>, ?> entry : channelOptions.entrySet()) {
// Every entry in the map is obtained from
// NettyChannelBuilder#withOption(ChannelOption<T> option, T value)
// so it is safe to pass the key-value pair to b.option().
b.option((ChannelOption<Object>) entry.getKey(), entry.getValue());
}
ChannelHandler bufferingHandler = new WriteBufferingAndExceptionHandler(negotiationHandler);
/**
* We don't use a ChannelInitializer in the client bootstrap because its "initChannel" method
* is executed in the event loop and we need this handler to be in the pipeline immediately so
* that it may begin buffering writes.
*/
b.handler(bufferingHandler);
ChannelFuture regFuture = b.register();
if (regFuture.isDone() && !regFuture.isSuccess()) {
channel = null;
// Initialization has failed badly. All new streams should be made to fail.
Throwable t = regFuture.cause();
if (t == null) {
t = new IllegalStateException("Channel is null, but future doesn't have a cause");
}
statusExplainingWhyTheChannelIsNull = Utils.statusFromThrowable(t);
// Use a Runnable since lifecycleManager calls transportListener
return new Runnable() {
@Override
public void run() {
// NOTICE: we not are calling lifecycleManager from the event loop. But there isn't really
// an event loop in this case, so nothing should be accessing the lifecycleManager. We
// could use GlobalEventExecutor (which is what regFuture would use for notifying
// listeners in this case), but avoiding on-demand thread creation in an error case seems
// a good idea and is probably clearer threading.
lifecycleManager.notifyTerminated(statusExplainingWhyTheChannelIsNull);
}
};
}
channel = regFuture.channel();
// Start the write queue as soon as the channel is constructed
handler.startWriteQueue(channel);
// This write will have no effect, yet it will only complete once the negotiationHandler
// flushes any pending writes. We need it to be staged *before* the `connect` so that
// the channel can't have been closed yet, removing all handlers. This write will sit in the
// AbstractBufferingHandler's buffer, and will either be flushed on a successful connection,
// or failed if the connection fails.
channel.writeAndFlush(NettyClientHandler.NOOP_MESSAGE).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
// Need to notify of this failure, because NettyClientHandler may not have been added to
// the pipeline before the error occurred.
lifecycleManager.notifyTerminated(Utils.statusFromThrowable(future.cause()));
}
}
});
// Start the connection operation to the server.
SocketAddress localAddress = localSocketPicker.createSocketAddress(remoteAddress, eagAttributes);
if (localAddress != null) {
channel.connect(remoteAddress, localAddress);
} else {
channel.connect(remoteAddress);
}
if (keepAliveManager != null) {
keepAliveManager.onTransportStarted();
}
return null;
}
use of io.grpc.internal.KeepAliveManager.ClientKeepAlivePinger in project grpc-java by grpc.
the class OkHttpClientTransport method start.
@Override
public Runnable start(Listener listener) {
this.listener = Preconditions.checkNotNull(listener, "listener");
if (enableKeepAlive) {
scheduler = SharedResourceHolder.get(TIMER_SERVICE);
keepAliveManager = new KeepAliveManager(new ClientKeepAlivePinger(this), scheduler, keepAliveTimeNanos, keepAliveTimeoutNanos, keepAliveWithoutCalls);
keepAliveManager.onTransportStarted();
}
if (isForTest()) {
synchronized (lock) {
frameWriter = new ExceptionHandlingFrameWriter(OkHttpClientTransport.this, testFrameWriter, testFrameLogger);
outboundFlow = new OutboundFlowController(OkHttpClientTransport.this, frameWriter);
}
serializingExecutor.execute(new Runnable() {
@Override
public void run() {
if (connectingCallback != null) {
connectingCallback.run();
}
clientFrameHandler = new ClientFrameHandler(testFrameReader, testFrameLogger);
executor.execute(clientFrameHandler);
synchronized (lock) {
maxConcurrentStreams = Integer.MAX_VALUE;
startPendingStreams();
}
connectedFuture.set(null);
}
});
return null;
}
final AsyncSink asyncSink = AsyncSink.sink(serializingExecutor, this);
final Variant variant = new Http2();
FrameWriter rawFrameWriter = variant.newWriter(Okio.buffer(asyncSink), true);
synchronized (lock) {
frameWriter = new ExceptionHandlingFrameWriter(this, rawFrameWriter);
outboundFlow = new OutboundFlowController(this, frameWriter);
}
final CountDownLatch latch = new CountDownLatch(1);
// Connecting in the serializingExecutor, so that some stream operations like synStream
// will be executed after connected.
serializingExecutor.execute(new Runnable() {
@Override
public void run() {
// initial preface.
try {
latch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// Use closed source on failure so that the reader immediately shuts down.
BufferedSource source = Okio.buffer(new Source() {
@Override
public long read(Buffer sink, long byteCount) {
return -1;
}
@Override
public Timeout timeout() {
return Timeout.NONE;
}
@Override
public void close() {
}
});
Socket sock;
SSLSession sslSession = null;
try {
if (proxiedAddr == null) {
sock = socketFactory.createSocket(address.getAddress(), address.getPort());
} else {
if (proxiedAddr.getProxyAddress() instanceof InetSocketAddress) {
sock = createHttpProxySocket(proxiedAddr.getTargetAddress(), (InetSocketAddress) proxiedAddr.getProxyAddress(), proxiedAddr.getUsername(), proxiedAddr.getPassword());
} else {
throw Status.INTERNAL.withDescription("Unsupported SocketAddress implementation " + proxiedAddr.getProxyAddress().getClass()).asException();
}
}
if (sslSocketFactory != null) {
SSLSocket sslSocket = OkHttpTlsUpgrader.upgrade(sslSocketFactory, hostnameVerifier, sock, getOverridenHost(), getOverridenPort(), connectionSpec);
sslSession = sslSocket.getSession();
sock = sslSocket;
}
sock.setTcpNoDelay(true);
source = Okio.buffer(Okio.source(sock));
asyncSink.becomeConnected(Okio.sink(sock), sock);
// The return value of OkHttpTlsUpgrader.upgrade is an SSLSocket that has this info
attributes = attributes.toBuilder().set(Grpc.TRANSPORT_ATTR_REMOTE_ADDR, sock.getRemoteSocketAddress()).set(Grpc.TRANSPORT_ATTR_LOCAL_ADDR, sock.getLocalSocketAddress()).set(Grpc.TRANSPORT_ATTR_SSL_SESSION, sslSession).set(GrpcAttributes.ATTR_SECURITY_LEVEL, sslSession == null ? SecurityLevel.NONE : SecurityLevel.PRIVACY_AND_INTEGRITY).build();
} catch (StatusException e) {
startGoAway(0, ErrorCode.INTERNAL_ERROR, e.getStatus());
return;
} catch (Exception e) {
onException(e);
return;
} finally {
clientFrameHandler = new ClientFrameHandler(variant.newReader(source, true));
}
synchronized (lock) {
socket = Preconditions.checkNotNull(sock, "socket");
if (sslSession != null) {
securityInfo = new InternalChannelz.Security(new InternalChannelz.Tls(sslSession));
}
}
}
});
// Schedule to send connection preface & settings before any other write.
try {
sendConnectionPrefaceAndSettings();
} finally {
latch.countDown();
}
serializingExecutor.execute(new Runnable() {
@Override
public void run() {
// ClientFrameHandler need to be started after connectionPreface / settings, otherwise it
// may send goAway immediately.
executor.execute(clientFrameHandler);
synchronized (lock) {
maxConcurrentStreams = Integer.MAX_VALUE;
startPendingStreams();
}
}
});
return null;
}
use of io.grpc.internal.KeepAliveManager.ClientKeepAlivePinger in project grpc-java by grpc.
the class KeepAliveManagerTest method clientKeepAlivePinger_pingTimeout.
@Test
public void clientKeepAlivePinger_pingTimeout() {
ConnectionClientTransport transport = mock(ConnectionClientTransport.class);
keepAlivePinger = new ClientKeepAlivePinger(transport);
keepAlivePinger.onPingTimeout();
ArgumentCaptor<Status> statusCaptor = ArgumentCaptor.forClass(Status.class);
verify(transport).shutdownNow(statusCaptor.capture());
Status status = statusCaptor.getValue();
assertThat(status.getCode()).isEqualTo(Status.Code.UNAVAILABLE);
assertThat(status.getDescription()).isEqualTo("Keepalive failed. The connection is likely gone");
}
use of io.grpc.internal.KeepAliveManager.ClientKeepAlivePinger in project grpc-java by grpc.
the class KeepAliveManagerTest method clientKeepAlivePinger_pingFailure.
@Test
public void clientKeepAlivePinger_pingFailure() {
ConnectionClientTransport transport = mock(ConnectionClientTransport.class);
keepAlivePinger = new ClientKeepAlivePinger(transport);
keepAlivePinger.ping();
ArgumentCaptor<ClientTransport.PingCallback> pingCallbackCaptor = ArgumentCaptor.forClass(ClientTransport.PingCallback.class);
verify(transport).ping(pingCallbackCaptor.capture(), isA(Executor.class));
ClientTransport.PingCallback pingCallback = pingCallbackCaptor.getValue();
pingCallback.onFailure(new Throwable());
ArgumentCaptor<Status> statusCaptor = ArgumentCaptor.forClass(Status.class);
verify(transport).shutdownNow(statusCaptor.capture());
Status status = statusCaptor.getValue();
assertThat(status.getCode()).isEqualTo(Status.Code.UNAVAILABLE);
assertThat(status.getDescription()).isEqualTo("Keepalive failed. The connection is likely gone");
}
Aggregations