Search in sources :

Example 11 with CircuitBreaker

use of com.nike.fastbreak.CircuitBreaker in project riposte by Nike-Inc.

the class AsyncHttpClientHelper method executeAsyncHttpRequest.

/**
 * Executes the given request asynchronously, handling the response with the given responseHandlerFunction, and
 * returns a {@link CompletableFuture} that represents the result of executing the
 * responseHandlerFunction on the downstream response. Any error anywhere along the way will cause the returned
 * future to be completed with {@link CompletableFuture#completeExceptionally(Throwable)}.
 * <p/>
 * <b>Distributed Tracing and MDC for the downstream call:</b> The given {@code distributedTraceStackForCall} and
 * {@code mdcContextForCall} arguments are used to setup distributed trace and MDC info for the downstream call so
 * that the callback will be performed with that data attached to whatever thread the callback is done on.
 */
public <O> CompletableFuture<O> executeAsyncHttpRequest(RequestBuilderWrapper requestBuilderWrapper, AsyncResponseHandler<O> responseHandlerFunction, Deque<Span> distributedTraceStackForCall, Map<String, String> mdcContextForCall) {
    CompletableFuture<O> completableFutureResponse = new CompletableFuture<>();
    try {
        Optional<ManualModeTask<Response>> circuitBreakerManualTask = getCircuitBreaker(requestBuilderWrapper).map(CircuitBreaker::newManualModeTask);
        // If we have a circuit breaker, give it a chance to throw an exception if the circuit is open/tripped
        circuitBreakerManualTask.ifPresent(ManualModeTask::throwExceptionIfCircuitBreakerIsOpen);
        // Setup the async completion handler for the call.
        AsyncCompletionHandlerWithTracingAndMdcSupport<O> asyncCompletionHandler = new AsyncCompletionHandlerWithTracingAndMdcSupport<>(completableFutureResponse, responseHandlerFunction, performSubSpanAroundDownstreamCalls, requestBuilderWrapper, circuitBreakerManualTask, distributedTraceStackForCall, mdcContextForCall, spanNamingAndTaggingStrategy);
        // Add distributed trace headers to the downstream call if we have a span.
        Span spanForCall = asyncCompletionHandler.getSpanForCall();
        if (spanForCall != null) {
            HttpRequestTracingUtils.propagateTracingHeaders((headerKey, headerValue) -> {
                if (headerValue != null) {
                    requestBuilderWrapper.requestBuilder.setHeader(headerKey, headerValue);
                }
            }, spanForCall);
        }
        // Add span tags if we're doing a subspan around the call.
        if (performSubSpanAroundDownstreamCalls && spanForCall != null) {
            spanNamingAndTaggingStrategy.handleRequestTagging(spanForCall, requestBuilderWrapper);
        }
        // Execute the downstream call. The completableFutureResponse will be completed or completed exceptionally
        // depending on the result of the call.
        requestBuilderWrapper.requestBuilder.execute(asyncCompletionHandler);
    } catch (Throwable t) {
        // normal when the circuit breaker associated with this request has been tripped.
        if (!(t instanceof CircuitBreakerOpenException)) {
            logger.error("An error occurred while trying to set up an async HTTP call for method {} and URL {}. " + "The CompletableFuture will be instantly failed with this error", requestBuilderWrapper.httpMethod, requestBuilderWrapper.url, t);
        }
        completableFutureResponse.completeExceptionally(t);
    }
    return completableFutureResponse;
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) CircuitBreaker(com.nike.fastbreak.CircuitBreaker) ManualModeTask(com.nike.fastbreak.CircuitBreaker.ManualModeTask) Span(com.nike.wingtips.Span) CircuitBreakerOpenException(com.nike.fastbreak.exception.CircuitBreakerOpenException)

Example 12 with CircuitBreaker

use of com.nike.fastbreak.CircuitBreaker in project riposte by Nike-Inc.

the class AsyncCompletionHandlerWithTracingAndMdcSupportTest method constructor_sets_values_exactly_as_given_when_subtracing_is_off.

@Test
public void constructor_sets_values_exactly_as_given_when_subtracing_is_off() {
    // given
    CompletableFuture cfResponse = mock(CompletableFuture.class);
    AsyncResponseHandler responseHandlerFunc = mock(AsyncResponseHandler.class);
    RequestBuilderWrapper rbwMock = mock(RequestBuilderWrapper.class);
    Optional<CircuitBreaker<Response>> circuitBreaker = Optional.of(mock(CircuitBreaker.class));
    Deque<Span> spanStack = mock(Deque.class);
    Map<String, String> mdcInfo = mock(Map.class);
    Deque<Span> spanStackBeforeCall = Tracer.getInstance().getCurrentSpanStackCopy();
    Map<String, String> mdcInfoBeforeCall = MDC.getCopyOfContextMap();
    // when
    AsyncCompletionHandlerWithTracingAndMdcSupport instance = new AsyncCompletionHandlerWithTracingAndMdcSupport(cfResponse, responseHandlerFunc, false, rbwMock, circuitBreaker, spanStack, mdcInfo, tagAndNamingStrategy);
    // then
    assertThat(instance.completableFutureResponse).isSameAs(cfResponse);
    assertThat(instance.responseHandlerFunction).isSameAs(responseHandlerFunc);
    assertThat(instance.performSubSpanAroundDownstreamCalls).isEqualTo(false);
    assertThat(instance.circuitBreakerManualTask).isSameAs(circuitBreaker);
    assertThat(instance.distributedTraceStackToUse).isSameAs(spanStack);
    assertThat(instance.mdcContextToUse).isSameAs(mdcInfo);
    assertThat(Tracer.getInstance().getCurrentSpanStackCopy()).isEqualTo(spanStackBeforeCall);
    assertThat(MDC.getCopyOfContextMap()).isEqualTo(mdcInfoBeforeCall);
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) CircuitBreaker(com.nike.fastbreak.CircuitBreaker) Span(com.nike.wingtips.Span) Test(org.junit.Test)

Example 13 with CircuitBreaker

use of com.nike.fastbreak.CircuitBreaker in project riposte by Nike-Inc.

the class AsyncCompletionHandlerWithTracingAndMdcSupportTest method constructor_sets_values_with_subspan_when_subtracing_is_on.

@DataProvider(value = { "NULL", "EMPTY", "HAS_EXISTING_SPAN" }, splitBy = "\\|")
@Test
public void constructor_sets_values_with_subspan_when_subtracing_is_on(ExistingSpanStackState existingSpanStackState) {
    // given
    CompletableFuture cfResponse = mock(CompletableFuture.class);
    AsyncResponseHandler responseHandlerFunc = mock(AsyncResponseHandler.class);
    RequestBuilderWrapper rbwMock = mock(RequestBuilderWrapper.class);
    Optional<CircuitBreaker<Response>> circuitBreaker = Optional.of(mock(CircuitBreaker.class));
    Span initialSpan = null;
    switch(existingSpanStackState) {
        case NULL:
        case // intentional fall-through
        EMPTY:
            resetTracingAndMdc();
            break;
        case HAS_EXISTING_SPAN:
            initialSpan = Tracer.getInstance().startRequestWithRootSpan("overallReqSpan");
            break;
        default:
            throw new IllegalArgumentException("Unhandled state: " + existingSpanStackState.name());
    }
    Deque<Span> spanStack = (existingSpanStackState == EMPTY) ? new LinkedList<>() : Tracer.getInstance().getCurrentSpanStackCopy();
    Map<String, String> mdcInfo = (existingSpanStackState == EMPTY) ? new HashMap<>() : MDC.getCopyOfContextMap();
    resetTracingAndMdc();
    Deque<Span> spanStackBeforeCall = Tracer.getInstance().getCurrentSpanStackCopy();
    Map<String, String> mdcInfoBeforeCall = MDC.getCopyOfContextMap();
    // when
    AsyncCompletionHandlerWithTracingAndMdcSupport instance = new AsyncCompletionHandlerWithTracingAndMdcSupport(cfResponse, responseHandlerFunc, true, rbwMock, circuitBreaker, spanStack, mdcInfo, tagAndNamingStrategy);
    // then
    assertThat(instance.completableFutureResponse).isSameAs(cfResponse);
    assertThat(instance.responseHandlerFunction).isSameAs(responseHandlerFunc);
    assertThat(instance.performSubSpanAroundDownstreamCalls).isEqualTo(true);
    assertThat(instance.circuitBreakerManualTask).isSameAs(circuitBreaker);
    int initialSpanStackSize = (spanStack == null) ? 0 : spanStack.size();
    assertThat(instance.distributedTraceStackToUse).hasSize(initialSpanStackSize + 1);
    Span subspan = (Span) instance.distributedTraceStackToUse.peek();
    assertThat(instance.mdcContextToUse.get(SpanFieldForLoggerMdc.TRACE_ID.mdcKey)).isEqualTo(subspan.getTraceId());
    if (existingSpanStackState == ExistingSpanStackState.NULL || existingSpanStackState == EMPTY) {
        assertThat(instance.distributedTraceStackToUse).hasSize(1);
    } else {
        assertThat(instance.distributedTraceStackToUse.peekLast()).isEqualTo(initialSpan);
        assertThat(subspan).isNotEqualTo(initialSpan);
        assertThat(subspan.getTraceId()).isEqualTo(initialSpan.getTraceId());
        assertThat(subspan.getParentSpanId()).isEqualTo(initialSpan.getSpanId());
        assertThat(subspan.getSpanName()).isEqualTo(instance.getSubspanSpanName(rbwMock, tagAndNamingStrategy));
    }
    assertThat(Tracer.getInstance().getCurrentSpanStackCopy()).isEqualTo(spanStackBeforeCall);
    assertThat(MDC.getCopyOfContextMap()).isEqualTo(mdcInfoBeforeCall);
}
Also used : CircuitBreaker(com.nike.fastbreak.CircuitBreaker) Span(com.nike.wingtips.Span) CompletableFuture(java.util.concurrent.CompletableFuture) DataProvider(com.tngtech.java.junit.dataprovider.DataProvider) Test(org.junit.Test)

Example 14 with CircuitBreaker

use of com.nike.fastbreak.CircuitBreaker in project riposte by Nike-Inc.

the class AsyncHttpClientHelper method executeAsyncHttpRequest.

/**
 * Executes the given request asynchronously, handling the response with the given responseHandlerFunction, and
 * returns a {@link CompletableFuture} that represents the result of executing the
 * responseHandlerFunction on the downstream response. Any error anywhere along the way will cause the returned
 * future to be completed with {@link CompletableFuture#completeExceptionally(Throwable)}.
 * <p/>
 * <b>Distributed Tracing and MDC for the downstream call:</b> The given {@code distributedTraceStackForCall} and
 * {@code mdcContextForCall} arguments are used to setup distributed trace and MDC info for the downstream call so
 * that the callback will be performed with that data attached to whatever thread the callback is done on.
 */
public <O> CompletableFuture<O> executeAsyncHttpRequest(RequestBuilderWrapper requestBuilderWrapper, AsyncResponseHandler<O> responseHandlerFunction, Deque<Span> distributedTraceStackForCall, Map<String, String> mdcContextForCall) {
    CompletableFuture<O> completableFutureResponse = new CompletableFuture<>();
    try {
        Optional<ManualModeTask<Response>> circuitBreakerManualTask = getCircuitBreaker(requestBuilderWrapper).map(CircuitBreaker::newManualModeTask);
        // If we have a circuit breaker, give it a chance to throw an exception if the circuit is open/tripped
        circuitBreakerManualTask.ifPresent(ManualModeTask::throwExceptionIfCircuitBreakerIsOpen);
        // Setup the async completion handler for the call.
        AsyncCompletionHandlerWithTracingAndMdcSupport<O> asyncCompletionHandler = new AsyncCompletionHandlerWithTracingAndMdcSupport<>(completableFutureResponse, responseHandlerFunction, performSubSpanAroundDownstreamCalls, requestBuilderWrapper, circuitBreakerManualTask, distributedTraceStackForCall, mdcContextForCall, spanNamingAndTaggingStrategy);
        // Add distributed trace headers to the downstream call if we have a span.
        Span spanForCall = asyncCompletionHandler.getSpanForCall();
        if (spanForCall != null) {
            HttpRequestTracingUtils.propagateTracingHeaders((headerKey, headerValue) -> {
                if (headerValue != null) {
                    requestBuilderWrapper.requestBuilder.setHeader(headerKey, headerValue);
                }
            }, spanForCall);
        }
        // Add span tags if we're doing a subspan around the call.
        if (performSubSpanAroundDownstreamCalls && spanForCall != null) {
            spanNamingAndTaggingStrategy.handleRequestTagging(spanForCall, requestBuilderWrapper);
        }
        // Execute the downstream call. The completableFutureResponse will be completed or completed exceptionally
        // depending on the result of the call.
        requestBuilderWrapper.requestBuilder.execute(asyncCompletionHandler);
    } catch (Throwable t) {
        // normal when the circuit breaker associated with this request has been tripped.
        if (!(t instanceof CircuitBreakerOpenException)) {
            logger.error("An error occurred while trying to set up an async HTTP call for method {} and URL {}. " + "The CompletableFuture will be instantly failed with this error", requestBuilderWrapper.httpMethod, requestBuilderWrapper.url, t);
        }
        completableFutureResponse.completeExceptionally(t);
    }
    return completableFutureResponse;
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) CircuitBreaker(com.nike.fastbreak.CircuitBreaker) ManualModeTask(com.nike.fastbreak.CircuitBreaker.ManualModeTask) Span(com.nike.wingtips.Span) CircuitBreakerOpenException(com.nike.fastbreak.exception.CircuitBreakerOpenException)

Example 15 with CircuitBreaker

use of com.nike.fastbreak.CircuitBreaker in project riposte by Nike-Inc.

the class ProxyRouterEndpointExecutionHandler method getCircuitBreaker.

protected Optional<CircuitBreaker<HttpResponse>> getCircuitBreaker(DownstreamRequestFirstChunkInfo downstreamReqFirstChunkInfo, ChannelHandlerContext ctx) {
    if (downstreamReqFirstChunkInfo == null || downstreamReqFirstChunkInfo.disableCircuitBreaker)
        return Optional.empty();
    // custom one is not specified.
    if (downstreamReqFirstChunkInfo.customCircuitBreaker.isPresent())
        return downstreamReqFirstChunkInfo.customCircuitBreaker;
    // No custom circuit breaker. Use the default for the given request's host.
    EventLoop nettyEventLoop = ctx.channel().eventLoop();
    CircuitBreaker<Integer> defaultStatusCodeCircuitBreaker = getDefaultHttpStatusCodeCircuitBreakerForKey(downstreamReqFirstChunkInfo.host, Optional.ofNullable(nettyEventLoop), Optional.ofNullable(nettyEventLoop));
    return Optional.of(new CircuitBreakerDelegate<>(defaultStatusCodeCircuitBreaker, httpResponse -> (httpResponse == null ? null : httpResponse.status().code())));
}
Also used : 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) DistributedTracingConfig(com.nike.riposte.server.config.distributedtracing.DistributedTracingConfig) 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) EventLoop(io.netty.channel.EventLoop)

Aggregations

CircuitBreaker (com.nike.fastbreak.CircuitBreaker)15 Span (com.nike.wingtips.Span)10 CompletableFuture (java.util.concurrent.CompletableFuture)10 Test (org.junit.Test)9 DataProvider (com.tngtech.java.junit.dataprovider.DataProvider)7 ManualModeTask (com.nike.fastbreak.CircuitBreaker.ManualModeTask)6 CircuitBreakerDelegate (com.nike.fastbreak.CircuitBreakerDelegate)6 CircuitBreakerForHttpStatusCode.getDefaultHttpStatusCodeCircuitBreakerForKey (com.nike.fastbreak.CircuitBreakerForHttpStatusCode.getDefaultHttpStatusCodeCircuitBreakerForKey)4 CircuitBreakerOpenException (com.nike.fastbreak.exception.CircuitBreakerOpenException)4 Pair (com.nike.internal.util.Pair)4 ChannelAttributes (com.nike.riposte.server.channelpipeline.ChannelAttributes)4 HttpProcessingState (com.nike.riposte.server.http.HttpProcessingState)4 ChannelHandlerContext (io.netty.channel.ChannelHandlerContext)4 EventLoop (io.netty.channel.EventLoop)4 ArgumentMatchers.anyString (org.mockito.ArgumentMatchers.anyString)4 Response (com.ning.http.client.Response)3 HttpMethod (io.netty.handler.codec.http.HttpMethod)3 Deque (java.util.Deque)3 Map (java.util.Map)3 Optional (java.util.Optional)3