Search in sources :

Example 96 with CompletableFuture

use of java.util.concurrent.CompletableFuture in project jdk8u_jdk by JetBrains.

the class ConcurrentAssociateTest method testOnce.

private static void testOnce(String desc, BiConsumer<ConcurrentMap<Object, Object>, Object> associator) {
    ConcurrentHashMap<Object, Object> m = new ConcurrentHashMap<>();
    CountDownLatch s = new CountDownLatch(1);
    Supplier<Runnable> sr = () -> () -> {
        try {
            s.await();
        } catch (InterruptedException e) {
        }
        for (int i = 0; i < N; i++) {
            Object o = new X();
            associator.accept(m, o);
            if (!m.containsKey(o)) {
                throw new AssociationFailure(desc + " failed: entry does not exist");
            }
        }
    };
    int ps = Runtime.getRuntime().availableProcessors();
    Stream<CompletableFuture> runners = IntStream.range(0, ps).mapToObj(i -> sr.get()).map(CompletableFuture::runAsync);
    CompletableFuture all = CompletableFuture.allOf(runners.toArray(CompletableFuture[]::new));
    // Trigger the runners to start associating
    s.countDown();
    try {
        all.join();
    } catch (CompletionException e) {
        Throwable t = e.getCause();
        if (t instanceof AssociationFailure) {
            throw (AssociationFailure) t;
        } else {
            throw e;
        }
    }
}
Also used : IntStream(java.util.stream.IntStream) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Test(org.testng.annotations.Test) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) CompletionException(java.util.concurrent.CompletionException) Supplier(java.util.function.Supplier) ConcurrentMap(java.util.concurrent.ConcurrentMap) CountDownLatch(java.util.concurrent.CountDownLatch) Stream(java.util.stream.Stream) Map(java.util.Map) ThreadLocalRandom(java.util.concurrent.ThreadLocalRandom) BiConsumer(java.util.function.BiConsumer) CountDownLatch(java.util.concurrent.CountDownLatch) CompletableFuture(java.util.concurrent.CompletableFuture) CompletionException(java.util.concurrent.CompletionException) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Example 97 with CompletableFuture

use of java.util.concurrent.CompletableFuture in project riposte by Nike-Inc.

the class StreamingAsyncHttpClient method streamDownstreamCall.

/**
     * TODO: Fully document me.
     * <br/>
     * NOTE: The returned CompletableFuture will only be completed successfully if the connection to the downstream
     * server was successful and the initialRequestChunk was successfully written out. This has implications for
     * initialRequestChunk regarding releasing its reference count (i.e. calling {@link
     * io.netty.util.ReferenceCountUtil#release(Object)} and passing in initialRequestChunk). If the returned
     * CompletableFuture is successful it means initialRequestChunk's reference count will already be reduced by one
     * relative to when this method was called because it will have been passed to a successful {@link
     * ChannelHandlerContext#writeAndFlush(Object)} method call.
     * <p/>
     * Long story short - assume initialRequestChunk is an object with a reference count of x:
     * <ul>
     *     <li>
     *         If the returned CompletableFuture is successful, then when it completes successfully
     *         initialRequestChunk's reference count will be x - 1
     *     </li>
     *     <li>
     *         If the returned CompletableFuture is *NOT* successful, then when it completes initialRequestChunk's
     *         reference count will still be x
     *     </li>
     * </ul>
     */
public CompletableFuture<StreamingChannel> streamDownstreamCall(String downstreamHost, int downstreamPort, HttpRequest initialRequestChunk, boolean isSecureHttpsCall, boolean relaxedHttpsValidation, StreamingCallback callback, long downstreamCallTimeoutMillis, ChannelHandlerContext ctx) {
    CompletableFuture<StreamingChannel> streamingChannel = new CompletableFuture<>();
    initialRequestChunk.headers().set(HttpHeaders.Names.HOST, downstreamHost);
    boolean performSubSpanAroundDownstreamCalls = true;
    ObjectHolder<Long> beforeConnectionStartTimeNanos = new ObjectHolder<>();
    beforeConnectionStartTimeNanos.heldObject = System.nanoTime();
    // Create a connection to the downstream server.
    ChannelPool pool = getPooledChannelFuture(downstreamHost, downstreamPort);
    Future<Channel> channelFuture = pool.acquire();
    // Add a listener that kicks off the downstream call once the connection is completed.
    channelFuture.addListener(future -> {
        Pair<Deque<Span>, Map<String, String>> originalThreadInfo = null;
        try {
            originalThreadInfo = linkTracingAndMdcToCurrentThread(ctx);
            if (!future.isSuccess()) {
                try {
                    streamingChannel.completeExceptionally(new WrapperException("Unable to connect to downstream host: " + downstreamHost, future.cause()));
                } finally {
                    Channel ch = channelFuture.getNow();
                    if (ch != null) {
                        markChannelAsBroken(ch);
                        pool.release(ch);
                    }
                }
                return;
            }
            if (logger.isDebugEnabled()) {
                logger.debug("CONNECTION SETUP TIME NANOS: {}", (System.nanoTime() - beforeConnectionStartTimeNanos.heldObject));
            }
            if (performSubSpanAroundDownstreamCalls) {
                String spanName = getSubspanSpanName(initialRequestChunk.getMethod().name(), downstreamHost + ":" + downstreamPort + initialRequestChunk.getUri());
                if (Tracer.getInstance().getCurrentSpan() == null) {
                    Tracer.getInstance().startRequestWithRootSpan(spanName);
                } else {
                    Tracer.getInstance().startSubSpan(spanName, Span.SpanPurpose.CLIENT);
                }
            }
            Deque<Span> distributedSpanStackToUse = Tracer.getInstance().getCurrentSpanStackCopy();
            Map<String, String> mdcContextToUse = MDC.getCopyOfContextMap();
            Span spanForDownstreamCall = (distributedSpanStackToUse == null) ? null : distributedSpanStackToUse.peek();
            if (spanForDownstreamCall != null) {
                setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.TRACE_SAMPLED, String.valueOf(spanForDownstreamCall.isSampleable()));
                setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.TRACE_ID, spanForDownstreamCall.getTraceId());
                setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.SPAN_ID, spanForDownstreamCall.getSpanId());
                setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.PARENT_SPAN_ID, spanForDownstreamCall.getParentSpanId());
                setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.SPAN_NAME, spanForDownstreamCall.getSpanName());
            }
            Channel ch = channelFuture.getNow();
            if (logger.isDebugEnabled())
                logger.debug("Channel ID of the Channel pulled from the pool: {}", ch.toString());
            ch.eventLoop().execute(runnableWithTracingAndMdc(() -> {
                BiConsumer<String, Throwable> prepChannelErrorHandler = (errorMessage, cause) -> {
                    try {
                        streamingChannel.completeExceptionally(new WrapperException(errorMessage, cause));
                    } finally {
                        markChannelAsBroken(ch);
                        pool.release(ch);
                    }
                };
                try {
                    ObjectHolder<Boolean> callActiveHolder = new ObjectHolder<>();
                    callActiveHolder.heldObject = true;
                    ObjectHolder<Boolean> lastChunkSentDownstreamHolder = new ObjectHolder<>();
                    lastChunkSentDownstreamHolder.heldObject = false;
                    prepChannelForDownstreamCall(pool, ch, callback, distributedSpanStackToUse, mdcContextToUse, isSecureHttpsCall, relaxedHttpsValidation, performSubSpanAroundDownstreamCalls, downstreamCallTimeoutMillis, callActiveHolder, lastChunkSentDownstreamHolder);
                    logInitialRequestChunk(initialRequestChunk, downstreamHost, downstreamPort);
                    ChannelFuture writeFuture = ch.writeAndFlush(initialRequestChunk);
                    writeFuture.addListener(completedWriteFuture -> {
                        if (completedWriteFuture.isSuccess())
                            streamingChannel.complete(new StreamingChannel(ch, pool, callActiveHolder, lastChunkSentDownstreamHolder, distributedSpanStackToUse, mdcContextToUse));
                        else {
                            prepChannelErrorHandler.accept("Writing the first HttpRequest chunk to the downstream service failed.", completedWriteFuture.cause());
                            return;
                        }
                    });
                } catch (SSLException | NoSuchAlgorithmException | KeyStoreException ex) {
                    prepChannelErrorHandler.accept("Error setting up SSL context for downstream call", ex);
                    return;
                } catch (Throwable t) {
                    prepChannelErrorHandler.accept("An unexpected error occurred while prepping the channel pipeline for the downstream call", t);
                    return;
                }
            }, ctx));
        } catch (Throwable ex) {
            try {
                String errorMsg = "Error occurred attempting to send first chunk (headers/etc) downstream";
                Exception errorToFire = new WrapperException(errorMsg, ex);
                logger.warn(errorMsg, errorToFire);
                streamingChannel.completeExceptionally(errorToFire);
            } finally {
                Channel ch = channelFuture.getNow();
                if (ch != null) {
                    markChannelAsBroken(ch);
                    pool.release(ch);
                }
            }
        } finally {
            unlinkTracingAndMdcFromCurrentThread(originalThreadInfo);
        }
    });
    return streamingChannel;
}
Also used : ChannelFuture(io.netty.channel.ChannelFuture) AttributeKey(io.netty.util.AttributeKey) Span(com.nike.wingtips.Span) HttpHeaders(io.netty.handler.codec.http.HttpHeaders) DefaultThreadFactory(io.netty.util.concurrent.DefaultThreadFactory) ChannelInboundHandlerAdapter(io.netty.channel.ChannelInboundHandlerAdapter) HttpMessage(io.netty.handler.codec.http.HttpMessage) LoggerFactory(org.slf4j.LoggerFactory) TraceHeaders(com.nike.wingtips.TraceHeaders) Random(java.util.Random) KeyStoreException(java.security.KeyStoreException) AsyncNettyHelper.unlinkTracingAndMdcFromCurrentThread(com.nike.riposte.util.AsyncNettyHelper.unlinkTracingAndMdcFromCurrentThread) HttpObject(io.netty.handler.codec.http.HttpObject) HttpClientCodec(io.netty.handler.codec.http.HttpClientCodec) InetAddress(java.net.InetAddress) ChannelPromise(io.netty.channel.ChannelPromise) Map(java.util.Map) ThreadFactory(java.util.concurrent.ThreadFactory) SocketChannel(io.netty.channel.socket.SocketChannel) HttpObjectDecoder(io.netty.handler.codec.http.HttpObjectDecoder) HttpRequest(io.netty.handler.codec.http.HttpRequest) TrustManagerFactory(javax.net.ssl.TrustManagerFactory) DownstreamIdleChannelTimeoutException(com.nike.riposte.server.error.exception.DownstreamIdleChannelTimeoutException) ChannelHealthChecker(io.netty.channel.pool.ChannelHealthChecker) DownstreamChannelClosedUnexpectedlyException(com.nike.riposte.server.error.exception.DownstreamChannelClosedUnexpectedlyException) KeyStore(java.security.KeyStore) ChannelPipeline(io.netty.channel.ChannelPipeline) InetSocketAddress(java.net.InetSocketAddress) NioEventLoopGroup(io.netty.channel.nio.NioEventLoopGroup) List(java.util.List) SSLException(javax.net.ssl.SSLException) AbstractChannelPoolHandler(io.netty.channel.pool.AbstractChannelPoolHandler) LogLevel(io.netty.handler.logging.LogLevel) DefaultHttpResponse(io.netty.handler.codec.http.DefaultHttpResponse) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) HttpObjectEncoder(io.netty.handler.codec.http.HttpObjectEncoder) DefaultFullHttpResponse(io.netty.handler.codec.http.DefaultFullHttpResponse) HttpResponse(io.netty.handler.codec.http.HttpResponse) ChannelPoolMap(io.netty.channel.pool.ChannelPoolMap) NioSocketChannel(io.netty.channel.socket.nio.NioSocketChannel) HttpRequestEncoder(io.netty.handler.codec.http.HttpRequestEncoder) DownstreamIdleChannelTimeoutHandler(com.nike.riposte.client.asynchttp.netty.downstreampipeline.DownstreamIdleChannelTimeoutHandler) ChannelOption(io.netty.channel.ChannelOption) LoggingHandler(io.netty.handler.logging.LoggingHandler) Tracer(com.nike.wingtips.Tracer) CompletableFuture(java.util.concurrent.CompletableFuture) Errors(io.netty.channel.unix.Errors) Deque(java.util.Deque) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) EpollSocketChannel(io.netty.channel.epoll.EpollSocketChannel) AsyncNettyHelper.linkTracingAndMdcToCurrentThread(com.nike.riposte.util.AsyncNettyHelper.linkTracingAndMdcToCurrentThread) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) InsecureTrustManagerFactory(io.netty.handler.ssl.util.InsecureTrustManagerFactory) BiConsumer(java.util.function.BiConsumer) EpollEventLoopGroup(io.netty.channel.epoll.EpollEventLoopGroup) HttpContent(io.netty.handler.codec.http.HttpContent) Attribute(io.netty.util.Attribute) Logger(org.slf4j.Logger) EventLoopGroup(io.netty.channel.EventLoopGroup) CombinedChannelDuplexHandler(io.netty.channel.CombinedChannelDuplexHandler) SslContext(io.netty.handler.ssl.SslContext) Promise(io.netty.util.concurrent.Promise) HostnameResolutionException(com.nike.riposte.server.error.exception.HostnameResolutionException) Field(java.lang.reflect.Field) UnknownHostException(java.net.UnknownHostException) ChannelFuture(io.netty.channel.ChannelFuture) Epoll(io.netty.channel.epoll.Epoll) Consumer(java.util.function.Consumer) Channel(io.netty.channel.Channel) SimpleChannelPool(io.netty.channel.pool.SimpleChannelPool) Bootstrap(io.netty.bootstrap.Bootstrap) FullHttpResponse(io.netty.handler.codec.http.FullHttpResponse) WrapperException(com.nike.backstopper.exception.WrapperException) MDC(org.slf4j.MDC) SimpleChannelInboundHandler(io.netty.channel.SimpleChannelInboundHandler) NativeIoExceptionWrapper(com.nike.riposte.server.error.exception.NativeIoExceptionWrapper) AsyncNettyHelper.runnableWithTracingAndMdc(com.nike.riposte.util.AsyncNettyHelper.runnableWithTracingAndMdc) ChannelPool(io.netty.channel.pool.ChannelPool) SslContextBuilder(io.netty.handler.ssl.SslContextBuilder) ChannelHandler(io.netty.channel.ChannelHandler) Pair(com.nike.internal.util.Pair) AbstractChannelPoolMap(io.netty.channel.pool.AbstractChannelPoolMap) Future(io.netty.util.concurrent.Future) SimpleChannelPool(io.netty.channel.pool.SimpleChannelPool) ChannelPool(io.netty.channel.pool.ChannelPool) SocketChannel(io.netty.channel.socket.SocketChannel) NioSocketChannel(io.netty.channel.socket.nio.NioSocketChannel) EpollSocketChannel(io.netty.channel.epoll.EpollSocketChannel) Channel(io.netty.channel.Channel) Deque(java.util.Deque) Span(com.nike.wingtips.Span) KeyStoreException(java.security.KeyStoreException) DownstreamIdleChannelTimeoutException(com.nike.riposte.server.error.exception.DownstreamIdleChannelTimeoutException) DownstreamChannelClosedUnexpectedlyException(com.nike.riposte.server.error.exception.DownstreamChannelClosedUnexpectedlyException) SSLException(javax.net.ssl.SSLException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) HostnameResolutionException(com.nike.riposte.server.error.exception.HostnameResolutionException) UnknownHostException(java.net.UnknownHostException) WrapperException(com.nike.backstopper.exception.WrapperException) WrapperException(com.nike.backstopper.exception.WrapperException) CompletableFuture(java.util.concurrent.CompletableFuture) Map(java.util.Map) ChannelPoolMap(io.netty.channel.pool.ChannelPoolMap) AbstractChannelPoolMap(io.netty.channel.pool.AbstractChannelPoolMap) BiConsumer(java.util.function.BiConsumer)

Example 98 with CompletableFuture

use of java.util.concurrent.CompletableFuture in project riposte by Nike-Inc.

the class ProxyRouterEndpointExecutionHandler method doChannelRead.

@Override
public PipelineContinuationBehavior doChannelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get();
    Endpoint<?> endpoint = state.getEndpointForExecution();
    if (shouldHandleDoChannelReadMessage(msg, endpoint)) {
        ProxyRouterProcessingState proxyRouterState = getOrCreateProxyRouterProcessingState(ctx);
        ProxyRouterEndpoint endpointProxyRouter = ((ProxyRouterEndpoint) endpoint);
        RequestInfo<?> requestInfo = state.getRequestInfo();
        if (msg instanceof HttpRequest) {
            if (requestInfo instanceof RiposteInternalRequestInfo) {
                // Tell this RequestInfo that we'll be managing the release of content chunks, so that when
                //      RequestInfo.releaseAllResources() is called we don't have extra reference count removals.
                ((RiposteInternalRequestInfo) requestInfo).contentChunksWillBeReleasedExternally();
            }
            // We're supposed to start streaming. There may be pre-endpoint-execution validation logic or other work
            //      that needs to happen before the endpoint is executed, so set up the CompletableFuture for the
            //      endpoint call to only execute if the pre-endpoint-execution validation/work chain is successful.
            CompletableFuture<DownstreamRequestFirstChunkInfo> firstChunkFuture = state.getPreEndpointExecutionWorkChain().thenCompose(functionWithTracingAndMdc(aVoid -> endpointProxyRouter.getDownstreamRequestFirstChunkInfo(requestInfo, longRunningTaskExecutor, ctx), ctx));
            Long endpointTimeoutOverride = endpointProxyRouter.completableFutureTimeoutOverrideMillis();
            long callTimeoutValueToUse = (endpointTimeoutOverride == null) ? defaultCompletableFutureTimeoutMillis : endpointTimeoutOverride;
            // When the first chunk is ready, stream it downstream and set up what happens afterward.
            firstChunkFuture.whenComplete((downstreamRequestFirstChunkInfo, throwable) -> {
                Optional<ManualModeTask<HttpResponse>> circuitBreakerManualTask = getCircuitBreaker(downstreamRequestFirstChunkInfo, ctx).map(CircuitBreaker::newManualModeTask);
                StreamingCallback callback = new StreamingCallbackForCtx(ctx, circuitBreakerManualTask, endpointProxyRouter, requestInfo, proxyRouterState);
                if (throwable != null) {
                    // Something blew up trying to determine the first chunk info.
                    callback.unrecoverableErrorOccurred(throwable);
                } else if (!ctx.channel().isOpen()) {
                    // The channel was closed for some reason before we were able to start streaming.
                    String errorMsg = "The channel from the original caller was closed before we could begin the " + "downstream call.";
                    Exception channelClosedException = new RuntimeException(errorMsg);
                    runnableWithTracingAndMdc(() -> logger.warn(errorMsg), ctx).run();
                    callback.unrecoverableErrorOccurred(channelClosedException);
                } else {
                    try {
                        // Ok we have the first chunk info. Start by setting the downstream call info in the request
                        //      info (i.e. for access logs if desired)
                        requestInfo.addRequestAttribute(DOWNSTREAM_CALL_PATH_REQUEST_ATTR_KEY, HttpUtils.extractPath(downstreamRequestFirstChunkInfo.firstChunk.getUri()));
                        // Try our circuit breaker (if we have one).
                        Throwable circuitBreakerException = null;
                        try {
                            circuitBreakerManualTask.ifPresent(ManualModeTask::throwExceptionIfCircuitBreakerIsOpen);
                        } catch (Throwable t) {
                            circuitBreakerException = t;
                        }
                        if (circuitBreakerException == null) {
                            // No circuit breaker, or the breaker is closed. We can now stream the first chunk info.
                            String downstreamHost = downstreamRequestFirstChunkInfo.host;
                            int downstreamPort = downstreamRequestFirstChunkInfo.port;
                            HttpRequest downstreamRequestFirstChunk = downstreamRequestFirstChunkInfo.firstChunk;
                            boolean isSecureHttpsCall = downstreamRequestFirstChunkInfo.isHttps;
                            boolean relaxedHttpsValidation = downstreamRequestFirstChunkInfo.relaxedHttpsValidation;
                            // Tell the proxyRouterState about the streaming callback so that
                            //      callback.unrecoverableErrorOccurred(...) can be called in the case of an error
                            //      on subsequent chunks.
                            proxyRouterState.setStreamingCallback(callback);
                            // Setup the streaming channel future with everything it needs to kick off the
                            //      downstream request.
                            proxyRouterState.setStreamingStartTimeNanos(System.nanoTime());
                            CompletableFuture<StreamingChannel> streamingChannel = streamingAsyncHttpClient.streamDownstreamCall(downstreamHost, downstreamPort, downstreamRequestFirstChunk, isSecureHttpsCall, relaxedHttpsValidation, callback, callTimeoutValueToUse, ctx);
                            // Tell the streaming channel future what to do when it completes.
                            streamingChannel = streamingChannel.whenComplete((sc, cause) -> {
                                if (cause == null) {
                                    // Successfully connected and sent the first chunk. We can now safely let
                                    //      the remaining content chunks through for streaming.
                                    proxyRouterState.triggerChunkProcessing(sc);
                                } else {
                                    // Something blew up while connecting to the downstream server.
                                    callback.unrecoverableErrorOccurred(cause);
                                }
                            });
                            // Set the streaming channel future on the state so it can be connected to.
                            proxyRouterState.setStreamingChannelCompletableFuture(streamingChannel);
                        } else {
                            // Circuit breaker is tripped (or otherwise threw an unexpected exception). Immediately
                            //      short circuit the error back to the client.
                            callback.unrecoverableErrorOccurred(circuitBreakerException);
                        }
                    } catch (Throwable t) {
                        callback.unrecoverableErrorOccurred(t);
                    }
                }
            });
        } else if (msg instanceof HttpContent) {
            HttpContent msgContent = (HttpContent) msg;
            //      chunk-streaming behavior and subsequent cleanup for the given HttpContent.
            if (!releaseContentChunkIfStreamAlreadyFailed(msgContent, proxyRouterState)) {
                registerChunkStreamingAction(proxyRouterState, msgContent, ctx);
            }
        }
        return PipelineContinuationBehavior.DO_NOT_FIRE_CONTINUE_EVENT;
    }
    return PipelineContinuationBehavior.CONTINUE;
}
Also used : HttpRequest(io.netty.handler.codec.http.HttpRequest) Span(com.nike.wingtips.Span) LoggerFactory(org.slf4j.LoggerFactory) ResponseInfo(com.nike.riposte.server.http.ResponseInfo) HttpObject(io.netty.handler.codec.http.HttpObject) ProxyRouterEndpoint(com.nike.riposte.server.http.ProxyRouterEndpoint) Map(java.util.Map) HttpRequest(io.netty.handler.codec.http.HttpRequest) CompletionException(java.util.concurrent.CompletionException) EventLoop(io.netty.channel.EventLoop) DownstreamRequestFirstChunkInfo(com.nike.riposte.server.http.ProxyRouterEndpoint.DownstreamRequestFirstChunkInfo) BaseInboundHandlerWithTracingAndMdcSupport(com.nike.riposte.server.handler.base.BaseInboundHandlerWithTracingAndMdcSupport) Endpoint(com.nike.riposte.server.http.Endpoint) HttpUtils(com.nike.riposte.util.HttpUtils) StreamingChannel(com.nike.riposte.client.asynchttp.netty.StreamingAsyncHttpClient.StreamingChannel) ChannelAttributes(com.nike.riposte.server.channelpipeline.ChannelAttributes) CircuitBreaker(com.nike.fastbreak.CircuitBreaker) RiposteInternalRequestInfo(com.nike.riposte.server.http.impl.RiposteInternalRequestInfo) Optional(java.util.Optional) HttpResponse(io.netty.handler.codec.http.HttpResponse) StreamingCallback(com.nike.riposte.client.asynchttp.netty.StreamingAsyncHttpClient.StreamingCallback) HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) EventExecutor(io.netty.util.concurrent.EventExecutor) RequestInfo(com.nike.riposte.server.http.RequestInfo) CircuitBreakerDelegate(com.nike.fastbreak.CircuitBreakerDelegate) ManualModeTask(com.nike.fastbreak.CircuitBreaker.ManualModeTask) CompletableFuture(java.util.concurrent.CompletableFuture) StreamingAsyncHttpClient(com.nike.riposte.client.asynchttp.netty.StreamingAsyncHttpClient) PipelineContinuationBehavior(com.nike.riposte.server.handler.base.PipelineContinuationBehavior) Deque(java.util.Deque) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) AsyncNettyHelper(com.nike.riposte.util.AsyncNettyHelper) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) HttpContent(io.netty.handler.codec.http.HttpContent) Attribute(io.netty.util.Attribute) OutboundMessageSendHeadersChunkFromResponseInfo(com.nike.riposte.server.channelpipeline.message.OutboundMessageSendHeadersChunkFromResponseInfo) Logger(org.slf4j.Logger) Executor(java.util.concurrent.Executor) AsyncNettyHelper.executeOnlyIfChannelIsActive(com.nike.riposte.util.AsyncNettyHelper.executeOnlyIfChannelIsActive) CircuitBreakerForHttpStatusCode.getDefaultHttpStatusCodeCircuitBreakerForKey(com.nike.fastbreak.CircuitBreakerForHttpStatusCode.getDefaultHttpStatusCodeCircuitBreakerForKey) AsyncNettyHelper.functionWithTracingAndMdc(com.nike.riposte.util.AsyncNettyHelper.functionWithTracingAndMdc) ChannelFuture(io.netty.channel.ChannelFuture) ExecutionException(java.util.concurrent.ExecutionException) FullHttpResponse(io.netty.handler.codec.http.FullHttpResponse) WrapperException(com.nike.backstopper.exception.WrapperException) OutboundMessageSendContentChunk(com.nike.riposte.server.channelpipeline.message.OutboundMessageSendContentChunk) AsyncNettyHelper.runnableWithTracingAndMdc(com.nike.riposte.util.AsyncNettyHelper.runnableWithTracingAndMdc) LastOutboundMessageSendLastContentChunk(com.nike.riposte.server.channelpipeline.message.LastOutboundMessageSendLastContentChunk) Pair(com.nike.internal.util.Pair) ProxyRouterProcessingState(com.nike.riposte.server.http.ProxyRouterProcessingState) CircuitBreaker(com.nike.fastbreak.CircuitBreaker) StreamingCallback(com.nike.riposte.client.asynchttp.netty.StreamingAsyncHttpClient.StreamingCallback) HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) ProxyRouterProcessingState(com.nike.riposte.server.http.ProxyRouterProcessingState) DownstreamRequestFirstChunkInfo(com.nike.riposte.server.http.ProxyRouterEndpoint.DownstreamRequestFirstChunkInfo) CompletionException(java.util.concurrent.CompletionException) ExecutionException(java.util.concurrent.ExecutionException) WrapperException(com.nike.backstopper.exception.WrapperException) CompletableFuture(java.util.concurrent.CompletableFuture) ManualModeTask(com.nike.fastbreak.CircuitBreaker.ManualModeTask) ProxyRouterEndpoint(com.nike.riposte.server.http.ProxyRouterEndpoint) RiposteInternalRequestInfo(com.nike.riposte.server.http.impl.RiposteInternalRequestInfo) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) HttpContent(io.netty.handler.codec.http.HttpContent)

Example 99 with CompletableFuture

use of java.util.concurrent.CompletableFuture in project riposte by Nike-Inc.

the class NonblockingEndpointExecutionHandler method doChannelRead.

@Override
public PipelineContinuationBehavior doChannelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get();
    Endpoint<?> endpoint = state.getEndpointForExecution();
    if (shouldHandleDoChannelReadMessage(msg, endpoint)) {
        // We only do something when the last chunk of content has arrived.
        if (msg instanceof LastHttpContent) {
            NonblockingEndpoint nonblockingEndpoint = ((NonblockingEndpoint) endpoint);
            // We're supposed to execute the endpoint. There may be pre-endpoint-execution validation logic or
            //      other work that needs to happen before the endpoint is executed, so set up the
            //      CompletableFuture for the endpoint call to only execute if the pre-endpoint-execution
            //      validation/work chain is successful.
            RequestInfo<?> requestInfo = state.getRequestInfo();
            @SuppressWarnings("unchecked") CompletableFuture<ResponseInfo<?>> responseFuture = state.getPreEndpointExecutionWorkChain().thenCompose(functionWithTracingAndMdc(aVoid -> (CompletableFuture<ResponseInfo<?>>) nonblockingEndpoint.execute(requestInfo, longRunningTaskExecutor, ctx), ctx));
            // Register an on-completion callback so we can be notified when the CompletableFuture finishes.
            responseFuture.whenComplete((responseInfo, throwable) -> {
                if (throwable != null)
                    asyncErrorCallback(ctx, throwable);
                else
                    asyncCallback(ctx, responseInfo);
            });
            // Also schedule a timeout check with our Netty event loop to make sure we kill the
            //      CompletableFuture if it goes on too long.
            long timeoutValueToUse = (nonblockingEndpoint.completableFutureTimeoutOverrideMillis() == null) ? defaultCompletableFutureTimeoutMillis : nonblockingEndpoint.completableFutureTimeoutOverrideMillis();
            ScheduledFuture<?> responseTimeoutScheduledFuture = ctx.channel().eventLoop().schedule(() -> {
                if (!responseFuture.isDone()) {
                    runnableWithTracingAndMdc(() -> logger.error("A non-blocking endpoint's CompletableFuture did not finish within " + "the allotted timeout ({} milliseconds). Forcibly cancelling it.", timeoutValueToUse), ctx).run();
                    @SuppressWarnings("unchecked") Throwable errorToUse = nonblockingEndpoint.getCustomTimeoutExceptionCause(requestInfo, ctx);
                    if (errorToUse == null)
                        errorToUse = new NonblockingEndpointCompletableFutureTimedOut(timeoutValueToUse);
                    responseFuture.completeExceptionally(errorToUse);
                }
            }, timeoutValueToUse, TimeUnit.MILLISECONDS);
            /*
                    The problem with the scheduled timeout check is that it holds on to the RequestInfo,
                    ChannelHandlerContext, and a bunch of other stuff that *should* become garbage the instant the
                    request finishes, but because of the timeout check it has to wait until the check executes
                    before the garbage is collectable. In high volume servers the default 60 second timeout is way
                    too long and acts like a memory leak and results in garbage collection thrashing if the
                    available memory can be filled within the 60 second timeout. To combat this we cancel the
                    timeout future when the endpoint future finishes. Netty will remove the cancelled timeout future
                    from its scheduled list within a short time, thus letting the garbage be collected.
                */
            responseFuture.whenComplete((responseInfo, throwable) -> {
                if (!responseTimeoutScheduledFuture.isDone())
                    responseTimeoutScheduledFuture.cancel(false);
            });
        }
        //      completes (see asyncCallback() and asyncErrorCallback()).
        return PipelineContinuationBehavior.DO_NOT_FIRE_CONTINUE_EVENT;
    }
    //      error to be returned to the client.
    return PipelineContinuationBehavior.CONTINUE;
}
Also used : HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) EventExecutor(io.netty.util.concurrent.EventExecutor) RequestInfo(com.nike.riposte.server.http.RequestInfo) Logger(org.slf4j.Logger) Executor(java.util.concurrent.Executor) ScheduledFuture(io.netty.util.concurrent.ScheduledFuture) LoggerFactory(org.slf4j.LoggerFactory) AsyncNettyHelper.executeOnlyIfChannelIsActive(com.nike.riposte.util.AsyncNettyHelper.executeOnlyIfChannelIsActive) ResponseInfo(com.nike.riposte.server.http.ResponseInfo) CompletableFuture(java.util.concurrent.CompletableFuture) PipelineContinuationBehavior(com.nike.riposte.server.handler.base.PipelineContinuationBehavior) HttpObject(io.netty.handler.codec.http.HttpObject) AsyncNettyHelper.functionWithTracingAndMdc(com.nike.riposte.util.AsyncNettyHelper.functionWithTracingAndMdc) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) TimeUnit(java.util.concurrent.TimeUnit) NonblockingEndpointCompletableFutureTimedOut(com.nike.riposte.server.error.exception.NonblockingEndpointCompletableFutureTimedOut) BaseInboundHandlerWithTracingAndMdcSupport(com.nike.riposte.server.handler.base.BaseInboundHandlerWithTracingAndMdcSupport) Endpoint(com.nike.riposte.server.http.Endpoint) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) ChannelAttributes(com.nike.riposte.server.channelpipeline.ChannelAttributes) LastOutboundMessageSendFullResponseInfo(com.nike.riposte.server.channelpipeline.message.LastOutboundMessageSendFullResponseInfo) AsyncNettyHelper.runnableWithTracingAndMdc(com.nike.riposte.util.AsyncNettyHelper.runnableWithTracingAndMdc) NonblockingEndpoint(com.nike.riposte.server.http.NonblockingEndpoint) ResponseInfo(com.nike.riposte.server.http.ResponseInfo) LastOutboundMessageSendFullResponseInfo(com.nike.riposte.server.channelpipeline.message.LastOutboundMessageSendFullResponseInfo) HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) NonblockingEndpointCompletableFutureTimedOut(com.nike.riposte.server.error.exception.NonblockingEndpointCompletableFutureTimedOut) CompletableFuture(java.util.concurrent.CompletableFuture) NonblockingEndpoint(com.nike.riposte.server.http.NonblockingEndpoint)

Example 100 with CompletableFuture

use of java.util.concurrent.CompletableFuture in project riposte by Nike-Inc.

the class AsyncHttpClientHelperTest method executeAsyncHttpRequest_completes_future_if_exception_happens_during_setup.

@DataProvider(value = { "true", "false" }, splitBy = "\\|")
@Test
public void executeAsyncHttpRequest_completes_future_if_exception_happens_during_setup(boolean throwCircuitBreakerOpenException) {
    // given
    RuntimeException exToThrow = (throwCircuitBreakerOpenException) ? new CircuitBreakerOpenException("foo", "kaboom") : new RuntimeException("kaboom");
    doThrow(exToThrow).when(helperSpy).getCircuitBreaker(any(RequestBuilderWrapper.class));
    Logger loggerMock = mock(Logger.class);
    Whitebox.setInternalState(helperSpy, "logger", loggerMock);
    // when
    CompletableFuture result = helperSpy.executeAsyncHttpRequest(mock(RequestBuilderWrapper.class), mock(AsyncResponseHandler.class), null, null);
    // then
    assertThat(result).isCompletedExceptionally();
    Throwable ex = catchThrowable(result::get);
    assertThat(ex).isInstanceOf(ExecutionException.class).hasCause(exToThrow);
    if (throwCircuitBreakerOpenException)
        verifyZeroInteractions(loggerMock);
    else
        verify(loggerMock).error(anyString(), anyString(), anyString(), eq(exToThrow));
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) Assertions.catchThrowable(org.assertj.core.api.Assertions.catchThrowable) Logger(org.slf4j.Logger) ExecutionException(java.util.concurrent.ExecutionException) CircuitBreakerOpenException(com.nike.fastbreak.exception.CircuitBreakerOpenException) DataProvider(com.tngtech.java.junit.dataprovider.DataProvider) Test(org.junit.Test)

Aggregations

CompletableFuture (java.util.concurrent.CompletableFuture)301 Test (org.junit.Test)64 IOException (java.io.IOException)38 List (java.util.List)34 Test (org.testng.annotations.Test)33 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)28 DestinationName (com.yahoo.pulsar.common.naming.DestinationName)26 Logger (org.slf4j.Logger)26 Map (java.util.Map)25 ManagedLedgerException (org.apache.bookkeeper.mledger.ManagedLedgerException)25 LoggerFactory (org.slf4j.LoggerFactory)25 PersistentTopic (com.yahoo.pulsar.broker.service.persistent.PersistentTopic)24 ArrayList (java.util.ArrayList)24 ExecutionException (java.util.concurrent.ExecutionException)24 TimeUnit (java.util.concurrent.TimeUnit)24 ByteBuf (io.netty.buffer.ByteBuf)23 CountDownLatch (java.util.concurrent.CountDownLatch)21 PulsarClientException (com.yahoo.pulsar.client.api.PulsarClientException)20 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)20 Consumer (com.yahoo.pulsar.client.api.Consumer)19