Search in sources :

Example 6 with TimeoutTransportCallback

use of com.linkedin.r2.transport.http.client.TimeoutTransportCallback in project rest.li by linkedin.

the class HttpNettyClient method writeRequest.

private void writeRequest(RestRequest request, RequestContext requestContext, Map<String, String> wireAttrs, final TimeoutTransportCallback<RestResponse> callback) {
    State state = _state.get();
    if (state != State.RUNNING) {
        errorResponse(callback, new IllegalStateException("Client is " + state));
        return;
    }
    URI uri = request.getURI();
    String scheme = uri.getScheme();
    if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) {
        errorResponse(callback, new IllegalArgumentException("Unknown scheme: " + scheme + " (only http/https is supported)"));
        return;
    }
    String host = uri.getHost();
    int port = uri.getPort();
    if (port == -1) {
        port = "http".equalsIgnoreCase(scheme) ? HTTP_DEFAULT_PORT : HTTPS_DEFAULT_PORT;
    }
    final RestRequest newRequest = new RestRequestBuilder(request).overwriteHeaders(WireAttributeHelper.toWireAttributes(wireAttrs)).build();
    final SocketAddress address;
    try {
        // TODO investigate DNS resolution and timing
        InetAddress inetAddress = InetAddress.getByName(host);
        address = new InetSocketAddress(inetAddress, port);
        requestContext.putLocalAttr(R2Constants.REMOTE_SERVER_ADDR, inetAddress.getHostAddress());
    } catch (UnknownHostException e) {
        errorResponse(callback, e);
        return;
    }
    requestContext.putLocalAttr(R2Constants.HTTP_PROTOCOL_VERSION, HttpProtocolVersion.HTTP_1_1);
    final AsyncPool<Channel> pool;
    try {
        pool = _channelPoolManager.getPoolForAddress(address);
    } catch (IllegalStateException e) {
        errorResponse(callback, e);
        return;
    }
    final Cancellable pendingGet = pool.get(new Callback<Channel>() {

        @Override
        public void onSuccess(final Channel channel) {
            // This handler ensures the channel is returned to the pool at the end of the
            // Netty pipeline.
            channel.attr(ChannelPoolHandler.CHANNEL_POOL_ATTR_KEY).set(pool);
            callback.addTimeoutTask(new Runnable() {

                @Override
                public void run() {
                    AsyncPool<Channel> pool = channel.attr(ChannelPoolHandler.CHANNEL_POOL_ATTR_KEY).getAndRemove();
                    if (pool != null) {
                        pool.dispose(channel);
                    }
                }
            });
            // This handler invokes the callback with the response once it arrives.
            channel.attr(RAPResponseHandler.CALLBACK_ATTR_KEY).set(callback);
            final State state = _state.get();
            if (state == State.REQUESTS_STOPPING || state == State.SHUTDOWN) {
                // In this case, we acquired a channel from the pool as request processing is halting.
                // The shutdown task might not timeout this callback, since it may already have scanned
                // all the channels for pending requests before we set the callback as the channel
                // attachment.  The TimeoutTransportCallback ensures the user callback in never
                // invoked more than once, so it is safe to invoke it unconditionally.
                errorResponse(callback, new TimeoutException("Operation did not complete before shutdown"));
                return;
            }
            // here we want the exception in outbound operations to be passed back through pipeline so that
            // the user callback would be invoked with the exception and the channel can be put back into the pool
            channel.writeAndFlush(newRequest).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
        }

        @Override
        public void onError(Throwable e) {
            errorResponse(callback, e);
        }
    });
    if (pendingGet != null) {
        callback.addTimeoutTask(new Runnable() {

            @Override
            public void run() {
                pendingGet.cancel();
            }
        });
    }
}
Also used : UnknownHostException(java.net.UnknownHostException) InetSocketAddress(java.net.InetSocketAddress) Cancellable(com.linkedin.r2.util.Cancellable) NioSocketChannel(io.netty.channel.socket.nio.NioSocketChannel) Channel(io.netty.channel.Channel) URI(java.net.URI) RestRequest(com.linkedin.r2.message.rest.RestRequest) TimeoutRunnable(com.linkedin.r2.util.TimeoutRunnable) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) SocketAddress(java.net.SocketAddress) InetSocketAddress(java.net.InetSocketAddress) InetAddress(java.net.InetAddress) TimeoutException(java.util.concurrent.TimeoutException)

Example 7 with TimeoutTransportCallback

use of com.linkedin.r2.transport.http.client.TimeoutTransportCallback in project rest.li by linkedin.

the class HttpNettyStreamClient method doWriteRequest.

@Override
protected void doWriteRequest(Request request, RequestContext context, SocketAddress address, TimeoutTransportCallback<StreamResponse> callback) {
    final AsyncPool<Channel> pool;
    try {
        pool = _channelPoolManager.getPoolForAddress(address);
    } catch (IllegalStateException e) {
        errorResponse(callback, e);
        return;
    }
    context.putLocalAttr(R2Constants.HTTP_PROTOCOL_VERSION, HttpProtocolVersion.HTTP_1_1);
    Callback<Channel> getCallback = new ChannelPoolGetCallback(pool, request, callback);
    final Cancellable pendingGet = pool.get(getCallback);
    if (pendingGet != null) {
        callback.addTimeoutTask(() -> pendingGet.cancel());
    }
}
Also used : Cancellable(com.linkedin.r2.util.Cancellable) NioSocketChannel(io.netty.channel.socket.nio.NioSocketChannel) Channel(io.netty.channel.Channel)

Example 8 with TimeoutTransportCallback

use of com.linkedin.r2.transport.http.client.TimeoutTransportCallback in project rest.li by linkedin.

the class AbstractNettyStreamClient method writeRequestWithTimeout.

private void writeRequestWithTimeout(final StreamRequest request, RequestContext requestContext, Map<String, String> wireAttrs, TransportCallback<StreamResponse> callback) {
    StreamExecutionCallback executionCallback = new StreamExecutionCallback(_callbackExecutors, callback);
    // By wrapping the callback in a Timeout callback before passing it along, we deny the rest
    // of the code access to the unwrapped callback.  This ensures two things:
    // 1. The user callback will always be invoked, since the Timeout will eventually expire
    // 2. The user callback is never invoked more than once
    final TimeoutTransportCallback<StreamResponse> timeoutCallback = new TimeoutTransportCallback<StreamResponse>(_scheduler, _requestTimeout, TimeUnit.MILLISECONDS, executionCallback, _requestTimeoutMessage);
    final StreamRequest requestWithWireAttrHeaders = request.builder().overwriteHeaders(WireAttributeHelper.toWireAttributes(wireAttrs)).build(request.getEntityStream());
    // talk to legacy R2 servers without problem if they're just using restRequest (full request).
    if (isFullRequest(requestContext)) {
        Messages.toRestRequest(requestWithWireAttrHeaders, new Callback<RestRequest>() {

            @Override
            public void onError(Throwable e) {
                errorResponse(timeoutCallback, e);
            }

            @Override
            public void onSuccess(RestRequest restRequest) {
                writeRequest(restRequest, requestContext, timeoutCallback);
            }
        });
    } else {
        writeRequest(requestWithWireAttrHeaders, requestContext, timeoutCallback);
    }
}
Also used : RestRequest(com.linkedin.r2.message.rest.RestRequest) StreamResponse(com.linkedin.r2.message.stream.StreamResponse) StreamRequest(com.linkedin.r2.message.stream.StreamRequest)

Example 9 with TimeoutTransportCallback

use of com.linkedin.r2.transport.http.client.TimeoutTransportCallback in project rest.li by linkedin.

the class TestHttp2ProtocolUpgradeHandler method testChannelCloseBeforeUpgrade.

@Test(timeOut = 10000)
@SuppressWarnings("unchecked")
public void testChannelCloseBeforeUpgrade() throws Exception {
    Http2UpgradeHandler handler = new Http2UpgradeHandler();
    EmbeddedChannel channel = new EmbeddedChannel(handler);
    // Reads the upgrade request from the outbound buffer to ensure nothing in the buffer
    Assert.assertEquals(channel.outboundMessages().size(), 1);
    Assert.assertNotNull(channel.readOutbound());
    Assert.assertTrue(channel.outboundMessages().isEmpty());
    RequestWithCallback request = Mockito.mock(RequestWithCallback.class);
    TimeoutAsyncPoolHandle handle = Mockito.mock(TimeoutAsyncPoolHandle.class);
    TimeoutTransportCallback callback = Mockito.mock(TimeoutTransportCallback.class);
    Mockito.when(request.handle()).thenReturn(handle);
    Mockito.when(request.callback()).thenReturn(callback);
    // Write should not succeed before upgrade completes
    Assert.assertFalse(channel.writeOutbound(request));
    Assert.assertFalse(channel.finish());
    // Synchronously waiting for channel to close
    channel.close().sync();
    Mockito.verify(request).handle();
    Mockito.verify(request).callback();
    Mockito.verify(handle).dispose();
    Mockito.verify(callback).onResponse(Mockito.any(TransportResponse.class));
}
Also used : RequestWithCallback(com.linkedin.r2.transport.common.bridge.common.RequestWithCallback) TimeoutTransportCallback(com.linkedin.r2.transport.http.client.TimeoutTransportCallback) EmbeddedChannel(io.netty.channel.embedded.EmbeddedChannel) TransportResponse(com.linkedin.r2.transport.common.bridge.common.TransportResponse) TimeoutAsyncPoolHandle(com.linkedin.r2.transport.http.client.TimeoutAsyncPoolHandle) Test(org.testng.annotations.Test)

Example 10 with TimeoutTransportCallback

use of com.linkedin.r2.transport.http.client.TimeoutTransportCallback in project rest.li by linkedin.

the class AbstractNettyClient method writeRequest.

/**
 * This method calls the user defined method {@link AbstractNettyClient#doWriteRequest(Request, RequestContext, SocketAddress, Map, TimeoutTransportCallback, long)}
 * after having checked that the client is still running and resolved the DNS
 */
private void writeRequest(Req request, RequestContext requestContext, Map<String, String> wireAttrs, TransportCallback<Res> callback) {
    // Decorates callback
    TransportCallback<Res> executionCallback = getExecutionCallback(callback);
    TransportCallback<Res> shutdownAwareCallback = getShutdownAwareCallback(executionCallback);
    // Resolves request timeout
    long requestTimeout = HttpNettyClient.resolveRequestTimeout(requestContext, _requestTimeout);
    // By wrapping the callback in a Timeout callback before passing it along, we deny the rest
    // of the code access to the unwrapped callback.  This ensures two things:
    // 1. The user callback will always be invoked, since the Timeout will eventually expire
    // 2. The user callback is never invoked more than once
    TimeoutTransportCallback<Res> timeoutCallback = new TimeoutTransportCallback<>(_scheduler, requestTimeout, TimeUnit.MILLISECONDS, shutdownAwareCallback, "Exceeded request timeout of " + requestTimeout + "ms");
    // check lifecycle
    NettyClientState state = _state.get();
    if (state != NettyClientState.RUNNING) {
        errorResponse(callback, new IllegalStateException("Client is " + state));
        return;
    }
    // resolve address
    final SocketAddress address;
    try {
        TimingContextUtil.markTiming(requestContext, TIMING_KEY);
        address = HttpNettyClient.resolveAddress(request, requestContext);
        TimingContextUtil.markTiming(requestContext, TIMING_KEY);
    } catch (UnknownHostException | UnknownSchemeException e) {
        errorResponse(callback, e);
        return;
    }
    doWriteRequest(request, requestContext, address, wireAttrs, timeoutCallback, requestTimeout);
}
Also used : UnknownHostException(java.net.UnknownHostException) UnknownSchemeException(com.linkedin.r2.netty.common.UnknownSchemeException) TimeoutTransportCallback(com.linkedin.r2.transport.http.client.TimeoutTransportCallback) NettyClientState(com.linkedin.r2.netty.common.NettyClientState) SocketAddress(java.net.SocketAddress)

Aggregations

Cancellable (com.linkedin.r2.util.Cancellable)6 Channel (io.netty.channel.Channel)6 TimeoutTransportCallback (com.linkedin.r2.transport.http.client.TimeoutTransportCallback)4 RestRequest (com.linkedin.r2.message.rest.RestRequest)3 NioSocketChannel (io.netty.channel.socket.nio.NioSocketChannel)3 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)2 NettyClientState (com.linkedin.r2.netty.common.NettyClientState)2 RequestWithCallback (com.linkedin.r2.transport.common.bridge.common.RequestWithCallback)2 TransportResponse (com.linkedin.r2.transport.common.bridge.common.TransportResponse)2 TimeoutAsyncPoolHandle (com.linkedin.r2.transport.http.client.TimeoutAsyncPoolHandle)2 EmbeddedChannel (io.netty.channel.embedded.EmbeddedChannel)2 SocketAddress (java.net.SocketAddress)2 UnknownHostException (java.net.UnknownHostException)2 TimeoutException (java.util.concurrent.TimeoutException)2 Test (org.testng.annotations.Test)2 StreamRequest (com.linkedin.r2.message.stream.StreamRequest)1 StreamResponse (com.linkedin.r2.message.stream.StreamResponse)1 UnknownSchemeException (com.linkedin.r2.netty.common.UnknownSchemeException)1 TransportCallback (com.linkedin.r2.transport.common.bridge.common.TransportCallback)1 AsyncPool (com.linkedin.r2.transport.http.client.AsyncPool)1