Search in sources :

Example 1 with NettyClientState

use of com.linkedin.r2.netty.common.NettyClientState in project rest.li by linkedin.

the class HttpNettyClient method sendRequest.

/**
 * Sends the request to the {@link ChannelPipeline}.
 */
private void sendRequest(Request request, RequestContext requestContext, Map<String, String> wireAttrs, TransportCallback<StreamResponse> callback) {
    final TransportCallback<StreamResponse> decoratedCallback = decorateUserCallback(request, callback);
    final NettyClientState state = _state.get();
    if (state != NettyClientState.RUNNING) {
        decoratedCallback.onResponse(TransportResponseImpl.error(new IllegalStateException("Client is not running")));
        return;
    }
    final long resolvedRequestTimeout = resolveRequestTimeout(requestContext, _requestTimeout);
    // Timeout ensures the request callback is always invoked and is cancelled before the
    // responsibility of invoking the callback is handed over to the pipeline.
    final Timeout<None> timeout = new Timeout<>(_scheduler, resolvedRequestTimeout, TimeUnit.MILLISECONDS, None.none());
    timeout.addTimeoutTask(() -> decoratedCallback.onResponse(TransportResponseImpl.error(new TimeoutException("Exceeded request timeout of " + resolvedRequestTimeout + "ms"))));
    // resolve address
    final SocketAddress address;
    try {
        TimingContextUtil.markTiming(requestContext, TIMING_KEY);
        address = resolveAddress(request, requestContext);
        TimingContextUtil.markTiming(requestContext, TIMING_KEY);
    } catch (Exception e) {
        decoratedCallback.onResponse(TransportResponseImpl.error(e));
        return;
    }
    // Serialize wire attributes
    final Request requestWithWireAttrHeaders;
    if (request instanceof StreamRequest) {
        requestWithWireAttrHeaders = buildRequestWithWireAttributes((StreamRequest) request, wireAttrs);
    } else {
        MessageType.setMessageType(MessageType.Type.REST, wireAttrs);
        requestWithWireAttrHeaders = buildRequestWithWireAttributes((RestRequest) request, wireAttrs);
    }
    // Gets channel pool
    final AsyncPool<Channel> pool;
    try {
        pool = getChannelPoolManagerPerRequest(requestWithWireAttrHeaders).getPoolForAddress(address);
    } catch (IllegalStateException e) {
        decoratedCallback.onResponse(TransportResponseImpl.error(e));
        return;
    }
    // Saves protocol version in request context
    requestContext.putLocalAttr(R2Constants.HTTP_PROTOCOL_VERSION, _protocolVersion);
    final Cancellable pendingGet = pool.get(new ChannelPoolGetCallback(pool, requestWithWireAttrHeaders, requestContext, decoratedCallback, timeout, resolvedRequestTimeout, _streamingTimeout));
    if (pendingGet != null) {
        timeout.addTimeoutTask(pendingGet::cancel);
    }
}
Also used : Timeout(com.linkedin.r2.util.Timeout) StreamingTimeout(com.linkedin.r2.netty.common.StreamingTimeout) Cancellable(com.linkedin.r2.util.Cancellable) StreamResponse(com.linkedin.r2.message.stream.StreamResponse) Channel(io.netty.channel.Channel) Request(com.linkedin.r2.message.Request) StreamRequest(com.linkedin.r2.message.stream.StreamRequest) RestRequest(com.linkedin.r2.message.rest.RestRequest) TimeoutException(java.util.concurrent.TimeoutException) ShutdownTimeoutException(com.linkedin.r2.netty.common.ShutdownTimeoutException) UnknownHostException(java.net.UnknownHostException) UnknownSchemeException(com.linkedin.r2.netty.common.UnknownSchemeException) StreamRequest(com.linkedin.r2.message.stream.StreamRequest) RestRequest(com.linkedin.r2.message.rest.RestRequest) NettyClientState(com.linkedin.r2.netty.common.NettyClientState) SocketAddress(java.net.SocketAddress) InetSocketAddress(java.net.InetSocketAddress) None(com.linkedin.common.util.None) TimeoutException(java.util.concurrent.TimeoutException) ShutdownTimeoutException(com.linkedin.r2.netty.common.ShutdownTimeoutException)

Example 2 with NettyClientState

use of com.linkedin.r2.netty.common.NettyClientState in project rest.li by linkedin.

the class HttpNettyClient method doWriteRequest.

@Override
protected void doWriteRequest(RestRequest request, RequestContext requestContext, SocketAddress address, Map<String, String> wireAttrs, final TimeoutTransportCallback<RestResponse> callback, long requestTimeout) {
    final RestRequest newRequest = new RestRequestBuilder(request).overwriteHeaders(WireAttributeHelper.toWireAttributes(wireAttrs)).build();
    requestContext.putLocalAttr(R2Constants.HTTP_PROTOCOL_VERSION, HttpProtocolVersion.HTTP_1_1);
    final AsyncPool<Channel> pool;
    try {
        pool = getChannelPoolManagerPerRequest(request).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(() -> {
                AsyncPool<Channel> pool1 = channel.attr(ChannelPoolHandler.CHANNEL_POOL_ATTR_KEY).getAndSet(null);
                if (pool1 != null) {
                    pool1.dispose(channel);
                }
            });
            TransportCallback<RestResponse> sslTimingCallback = SslHandshakeTimingHandler.getSslTimingCallback(channel, requestContext, callback);
            // This handler invokes the callback with the response once it arrives.
            channel.attr(RAPResponseHandler.CALLBACK_ATTR_KEY).set(sslTimingCallback);
            // Set the session validator requested by the user
            SslSessionValidator sslSessionValidator = (SslSessionValidator) requestContext.getLocalAttr(R2Constants.REQUESTED_SSL_SESSION_VALIDATOR);
            channel.attr(NettyChannelAttributes.SSL_SESSION_VALIDATOR).set(sslSessionValidator);
            final NettyClientState state = _state.get();
            if (state == NettyClientState.REQUESTS_STOPPING || state == NettyClientState.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(sslTimingCallback, new TimeoutException("Operation did not complete before shutdown"));
                // The channel is usually release in two places: timeout or in the netty pipeline.
                // Since we call the callback above, the timeout associated will be never invoked. On top of that
                // we never send the request to the pipeline (due to the return statement), and nobody is releasing the channel
                // until the channel is forcefully closed by the shutdownTimeout. Therefore we have to release it here
                AsyncPool<Channel> pool = channel.attr(ChannelPoolHandler.CHANNEL_POOL_ATTR_KEY).getAndSet(null);
                if (pool != null) {
                    pool.put(channel);
                }
                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(new ErrorChannelFutureListener());
        }

        @Override
        public void onError(Throwable e) {
            errorResponse(callback, e);
        }
    });
    if (pendingGet != null) {
        callback.addTimeoutTask(pendingGet::cancel);
    }
}
Also used : TimeoutTransportCallback(com.linkedin.r2.transport.http.client.TimeoutTransportCallback) TransportCallback(com.linkedin.r2.transport.common.bridge.common.TransportCallback) SslSessionValidator(com.linkedin.r2.transport.http.client.common.ssl.SslSessionValidator) Cancellable(com.linkedin.r2.util.Cancellable) Channel(io.netty.channel.Channel) RestRequest(com.linkedin.r2.message.rest.RestRequest) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) NettyClientState(com.linkedin.r2.netty.common.NettyClientState) AsyncPool(com.linkedin.r2.transport.http.client.AsyncPool) TimeoutException(java.util.concurrent.TimeoutException) ErrorChannelFutureListener(com.linkedin.r2.transport.http.client.common.ErrorChannelFutureListener)

Example 3 with NettyClientState

use of com.linkedin.r2.netty.common.NettyClientState 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

NettyClientState (com.linkedin.r2.netty.common.NettyClientState)3 RestRequest (com.linkedin.r2.message.rest.RestRequest)2 UnknownSchemeException (com.linkedin.r2.netty.common.UnknownSchemeException)2 TimeoutTransportCallback (com.linkedin.r2.transport.http.client.TimeoutTransportCallback)2 Cancellable (com.linkedin.r2.util.Cancellable)2 Channel (io.netty.channel.Channel)2 SocketAddress (java.net.SocketAddress)2 UnknownHostException (java.net.UnknownHostException)2 TimeoutException (java.util.concurrent.TimeoutException)2 None (com.linkedin.common.util.None)1 Request (com.linkedin.r2.message.Request)1 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)1 StreamRequest (com.linkedin.r2.message.stream.StreamRequest)1 StreamResponse (com.linkedin.r2.message.stream.StreamResponse)1 ShutdownTimeoutException (com.linkedin.r2.netty.common.ShutdownTimeoutException)1 StreamingTimeout (com.linkedin.r2.netty.common.StreamingTimeout)1 TransportCallback (com.linkedin.r2.transport.common.bridge.common.TransportCallback)1 AsyncPool (com.linkedin.r2.transport.http.client.AsyncPool)1 ErrorChannelFutureListener (com.linkedin.r2.transport.http.client.common.ErrorChannelFutureListener)1 SslSessionValidator (com.linkedin.r2.transport.http.client.common.ssl.SslSessionValidator)1