Search in sources :

Example 56 with Timeout

use of com.linkedin.r2.util.Timeout 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 57 with Timeout

use of com.linkedin.r2.util.Timeout 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 58 with Timeout

use of com.linkedin.r2.util.Timeout in project rest.li by linkedin.

the class TestChannelPoolStreamHandler method getChannel.

private static EmbeddedChannel getChannel() {
    EmbeddedChannel ch = new EmbeddedChannel(new RAPResponseDecoder(1000), new RAPStreamResponseHandler(), new ChannelPoolStreamHandler());
    ch.attr(RAPResponseDecoder.TIMEOUT_ATTR_KEY).set(new Timeout<None>(Executors.newSingleThreadScheduledExecutor(), 1000, TimeUnit.MILLISECONDS, None.none()));
    ch.attr(RAPStreamResponseHandler.CALLBACK_ATTR_KEY).set(response -> {
        StreamResponse streamResponse = response.getResponse();
        streamResponse.getEntityStream().setReader(new DrainReader());
    });
    return ch;
}
Also used : StreamResponse(com.linkedin.r2.message.stream.StreamResponse) EmbeddedChannel(io.netty.channel.embedded.EmbeddedChannel) None(com.linkedin.common.util.None) DrainReader(com.linkedin.r2.message.stream.entitystream.DrainReader)

Example 59 with Timeout

use of com.linkedin.r2.util.Timeout in project rest.li by linkedin.

the class SyncIOHandler method loop.

public void loop() throws ServletException, IOException {
    final long startTime = System.currentTimeMillis();
    byte[] buf = new byte[DEFAULT_DATA_CHUNK_SIZE];
    while (shouldContinue() && !_forceExit) {
        Event event;
        try {
            long timeSpent = System.currentTimeMillis() - startTime;
            long maxWaitTime = timeSpent < _timeout ? _timeout - timeSpent : 0;
            event = _eventQueue.poll(maxWaitTime, TimeUnit.MILLISECONDS);
            if (event == null) {
                throw new TimeoutException("Timeout after " + _timeout + " milliseconds.");
            }
        } catch (Exception ex) {
            throw new ServletException(ex);
        }
        switch(event.getEventType()) {
            case ResponseDataAvailable:
                {
                    ByteString data = (ByteString) event.getData();
                    data.write(_os);
                    _rh.request(1);
                    break;
                }
            case WriteRequestPossible:
                {
                    while (_wh.remaining() > 0) {
                        int actualLen = _is.read(buf);
                        if (actualLen < 0) {
                            _wh.done();
                            _requestReadFinished = true;
                            break;
                        }
                        _wh.write(ByteString.copy(buf, 0, actualLen));
                    }
                    break;
                }
            case FullResponseReceived:
                {
                    _os.close();
                    _responseWriteFinished = true;
                    break;
                }
            case ResponseDataError:
                {
                    _os.close();
                    _responseWriteFinished = true;
                    break;
                }
            case WriteRequestAborted:
                {
                    if (event.getData() instanceof AbortedException) {
                        // reader cancels, we'll drain the stream on behalf of reader
                        // we don't directly drain it here because we'd like to give other events
                        // some opportunities to be executed; e.g. return an error response
                        _eventQueue.add(Event.DrainRequestEvent);
                    } else {
                        // TODO: do we want to be smarter and return server error response?
                        throw new ServletException((Throwable) event.getData());
                    }
                    break;
                }
            case DrainRequest:
                {
                    for (int i = 0; i < 10; i++) {
                        int actualLen = _is.read(buf);
                        if (actualLen < 0) {
                            _requestReadFinished = true;
                            break;
                        }
                    }
                    if (!_requestReadFinished) {
                        // add self back to event queue and give others a chance to run
                        _eventQueue.add(Event.DrainRequestEvent);
                    }
                    break;
                }
            case ForceExit:
                {
                    _forceExit = true;
                    break;
                }
            default:
                throw new IllegalStateException("Unknown event type:" + event.getEventType());
        }
    }
}
Also used : ServletException(javax.servlet.ServletException) ByteString(com.linkedin.data.ByteString) AbortedException(com.linkedin.r2.message.stream.entitystream.AbortedException) ServletException(javax.servlet.ServletException) TimeoutException(java.util.concurrent.TimeoutException) IOException(java.io.IOException) AbortedException(com.linkedin.r2.message.stream.entitystream.AbortedException) TimeoutException(java.util.concurrent.TimeoutException)

Example 60 with Timeout

use of com.linkedin.r2.util.Timeout in project rest.li by linkedin.

the class TestClientShutdown method testShutdown.

@Test(dataProvider = "configs")
public void testShutdown(boolean clientROS, boolean serverROS, String protocolVersion) throws Exception {
    _clientFactory = new HttpClientFactory();
    Map<String, String> clientProperties = new HashMap<String, String>();
    // very long shutdown timeout
    clientProperties.put(HttpClientFactory.HTTP_SHUTDOWN_TIMEOUT, "60000");
    clientProperties.put(HttpClientFactory.HTTP_PROTOCOL_VERSION, protocolVersion);
    _client = new TransportClientAdapter(_clientFactory.getClient(clientProperties), clientROS);
    TransportDispatcher dispatcher = new TransportDispatcherBuilder().addRestHandler(ECHO_URI, new EchoHandler()).build();
    _server = new HttpServerFactory(HttpJettyServer.ServletType.RAP).createH2cServer(PORT, dispatcher, serverROS);
    try {
        _server.start();
        RestRequestBuilder builder = new RestRequestBuilder(URI.create("http://localhost:" + PORT + ECHO_URI));
        byte[] content = new byte[100];
        builder.setEntity(content);
        Future<RestResponse> future = _client.restRequest(builder.build());
        RestResponse response = future.get(30, TimeUnit.SECONDS);
        Assert.assertEquals(response.getEntity().copyBytes(), content);
        final FutureCallback<None> clientShutdownCallback = new FutureCallback<None>();
        _client.shutdown(clientShutdownCallback);
        // we should catch those clients that do not shutdown properly in 5 seconds
        clientShutdownCallback.get(5000, TimeUnit.MILLISECONDS);
        final FutureCallback<None> factoryShutdownCallback = new FutureCallback<None>();
        _clientFactory.shutdown(factoryShutdownCallback);
        factoryShutdownCallback.get();
    } finally {
        if (_server != null) {
            _server.stop();
            _server.waitForStop();
        }
    }
}
Also used : HttpServerFactory(com.linkedin.r2.transport.http.server.HttpServerFactory) HashMap(java.util.HashMap) RestResponse(com.linkedin.r2.message.rest.RestResponse) TransportDispatcher(com.linkedin.r2.transport.common.bridge.server.TransportDispatcher) TransportClientAdapter(com.linkedin.r2.transport.common.bridge.client.TransportClientAdapter) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) HttpClientFactory(com.linkedin.r2.transport.http.client.HttpClientFactory) TransportDispatcherBuilder(com.linkedin.r2.transport.common.bridge.server.TransportDispatcherBuilder) None(com.linkedin.common.util.None) FutureCallback(com.linkedin.common.callback.FutureCallback) Test(org.testng.annotations.Test)

Aggregations

Test (org.testng.annotations.Test)78 RequestContext (com.linkedin.r2.message.RequestContext)46 CountDownLatch (java.util.concurrent.CountDownLatch)40 TimeoutException (java.util.concurrent.TimeoutException)40 None (com.linkedin.common.util.None)33 FutureCallback (com.linkedin.common.callback.FutureCallback)32 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)26 StreamResponse (com.linkedin.r2.message.stream.StreamResponse)25 URI (java.net.URI)25 RestRequest (com.linkedin.r2.message.rest.RestRequest)21 StreamRequestBuilder (com.linkedin.r2.message.stream.StreamRequestBuilder)21 ByteString (com.linkedin.data.ByteString)19 HashMap (java.util.HashMap)19 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)19 RestResponse (com.linkedin.r2.message.rest.RestResponse)18 StreamRequest (com.linkedin.r2.message.stream.StreamRequest)17 ExecutionException (java.util.concurrent.ExecutionException)17 TransportClient (com.linkedin.r2.transport.common.bridge.client.TransportClient)15 IOException (java.io.IOException)15 TransportCallback (com.linkedin.r2.transport.common.bridge.common.TransportCallback)13