Search in sources :

Example 1 with DatarouterHttpCircuitBreakerException

use of io.datarouter.httpclient.response.exception.DatarouterHttpCircuitBreakerException in project datarouter by hotpads.

the class DatarouterHttpClientIoExceptionCircuitBreaker method call.

public DatarouterHttpResponse call(CloseableHttpClient httpClient, DatarouterHttpRequest request, Consumer<HttpEntity> httpEntityConsumer, HttpClientContext context, Supplier<Boolean> enableBreakers, Supplier<Boolean> traceInQueryString, Supplier<Boolean> debugLog) throws DatarouterHttpException {
    CircuitBreakerState state = getState();
    if (state == CircuitBreakerState.OPEN && enableBreakers.get()) {
        incrementCounterOnStateChange("open");
        throw new DatarouterHttpCircuitBreakerException(name, callResultQueue.getOriginalException());
    }
    DatarouterHttpException ex;
    TracerTool.startSpan("http call " + request.getPath(), TraceSpanGroupType.HTTP);
    Tracer tracer = TracerThreadLocal.get();
    W3TraceContext traceContext;
    if (tracer != null && tracer.getTraceContext().isPresent()) {
        traceContext = tracer.getTraceContext().get().copy();
        traceContext.updateParentIdAndAddTracestateMember();
    } else {
        count("traceContext null");
        traceContext = new W3TraceContext(Trace2Dto.getCurrentTimeInNs());
    }
    String traceparent = traceContext.getTraceparent().toString();
    if (traceInQueryString.get()) {
        request.addGetParam(TRACEPARENT, traceparent);
    }
    HttpRequestBase internalHttpRequest = request.getRequest();
    count("request");
    logger.debug("traceparent={} passing to request={}", traceparent, request.getPath());
    internalHttpRequest.addHeader(TRACEPARENT, traceparent);
    internalHttpRequest.addHeader(TRACESTATE, traceContext.getTracestate().toString());
    context.setAttribute(TRACEPARENT, traceContext.getTraceparent().toString());
    if (debugLog.get()) {
        logger.warn("sending http request method={} url={}", internalHttpRequest.getMethod(), internalHttpRequest.getURI());
    }
    long requestStartTimeNs = Trace2Dto.getCurrentTimeInNs();
    try {
        HttpResponse httpResponse = httpClient.execute(internalHttpRequest, context);
        Duration duration = Duration.ofNanos(Trace2Dto.getCurrentTimeInNs() - requestStartTimeNs);
        String entity = null;
        int statusCode = httpResponse.getStatusLine().getStatusCode();
        count("response " + statusCode);
        boolean isBadStatusCode = statusCode >= HttpStatus.SC_BAD_REQUEST;
        HttpEntity httpEntity = httpResponse.getEntity();
        if (httpEntity != null) {
            // skip the httpEntityConsumer in case of error because we are going to close the input stream
            if (httpEntityConsumer != null && !isBadStatusCode) {
                httpEntityConsumer.accept(httpEntity);
            } else {
                entity = EntityUtils.toString(httpEntity);
            }
        }
        Optional<Traceparent> remoteTraceparent = Optional.ofNullable(httpResponse.getFirstHeader(TRACEPARENT)).map(Header::getValue).map(Traceparent::parse).filter(Optional::isPresent).map(Optional::get);
        remoteTraceparent.ifPresent(tp -> TracerTool.appendToSpanInfo("remote parentId", tp.parentId));
        if (remoteTraceparent.isPresent() && remoteTraceparent.get().shouldSample()) {
            // if remote server has forced sample for trace, we also force sample the client's trace
            TracerTool.setForceSample();
        }
        if (duration.compareTo(LOG_SLOW_REQUEST_THRESHOLD) > 0) {
            logger.warn("Slow request target={} durationS={} remoteTraceparent={}", request.getPath(), duration.getSeconds(), remoteTraceparent.orElse(null));
        }
        DatarouterHttpResponse response = new DatarouterHttpResponse(httpResponse, context, statusCode, entity);
        if (isBadStatusCode) {
            TracerTool.appendToSpanInfo("bad status code", statusCode);
            ex = new DatarouterHttpResponseException(response, duration, traceparent, request.getPath());
            callResultQueue.insertFalseResultWithException(ex);
            // no need to abort the connection, we received a response line, the connection is probably still good
            response.tryClose();
            throw ex;
        }
        if (state == CircuitBreakerState.HALF_OPEN) {
            callResultQueue.reset();
            incrementCounterOnStateChange("closing");
            logger.error("Half opened circuit now closing. CircuitName={}", name);
        }
        callResultQueue.insertTrueResult();
        return response;
    } catch (IOException e) {
        count("IOException");
        TracerTool.appendToSpanInfo("exception", e.getMessage());
        ex = new DatarouterHttpConnectionAbortedException(e, TimeUnit.NANOSECONDS.toMillis(requestStartTimeNs), traceparent, request.getPath());
        callResultQueue.insertFalseResultWithException(ex);
    } catch (CancellationException e) {
        count("CancellationException");
        TracerTool.appendToSpanInfo("exception", e.getMessage());
        ex = new DatarouterHttpRequestInterruptedException(e, TimeUnit.NANOSECONDS.toMillis(requestStartTimeNs), traceparent, request.getPath());
        callResultQueue.insertFalseResultWithException(ex);
    } finally {
        TracerTool.finishSpan();
    }
    // connection might have gone bad, destroying it
    if (internalHttpRequest != null) {
        forceAbortRequestUnchecked(internalHttpRequest);
    }
    throw ex;
}
Also used : HttpRequestBase(org.apache.http.client.methods.HttpRequestBase) DatarouterHttpResponseException(io.datarouter.httpclient.response.exception.DatarouterHttpResponseException) DatarouterHttpRequestInterruptedException(io.datarouter.httpclient.response.exception.DatarouterHttpRequestInterruptedException) HttpEntity(org.apache.http.HttpEntity) Optional(java.util.Optional) Tracer(io.datarouter.instrumentation.trace.Tracer) DatarouterHttpCircuitBreakerException(io.datarouter.httpclient.response.exception.DatarouterHttpCircuitBreakerException) DatarouterHttpResponse(io.datarouter.httpclient.response.DatarouterHttpResponse) HttpResponse(org.apache.http.HttpResponse) W3TraceContext(io.datarouter.instrumentation.trace.W3TraceContext) Duration(java.time.Duration) IOException(java.io.IOException) Traceparent(io.datarouter.instrumentation.trace.Traceparent) DatarouterHttpResponse(io.datarouter.httpclient.response.DatarouterHttpResponse) DatarouterHttpConnectionAbortedException(io.datarouter.httpclient.response.exception.DatarouterHttpConnectionAbortedException) DatarouterHttpException(io.datarouter.httpclient.response.exception.DatarouterHttpException) CancellationException(java.util.concurrent.CancellationException)

Aggregations

DatarouterHttpResponse (io.datarouter.httpclient.response.DatarouterHttpResponse)1 DatarouterHttpCircuitBreakerException (io.datarouter.httpclient.response.exception.DatarouterHttpCircuitBreakerException)1 DatarouterHttpConnectionAbortedException (io.datarouter.httpclient.response.exception.DatarouterHttpConnectionAbortedException)1 DatarouterHttpException (io.datarouter.httpclient.response.exception.DatarouterHttpException)1 DatarouterHttpRequestInterruptedException (io.datarouter.httpclient.response.exception.DatarouterHttpRequestInterruptedException)1 DatarouterHttpResponseException (io.datarouter.httpclient.response.exception.DatarouterHttpResponseException)1 Traceparent (io.datarouter.instrumentation.trace.Traceparent)1 Tracer (io.datarouter.instrumentation.trace.Tracer)1 W3TraceContext (io.datarouter.instrumentation.trace.W3TraceContext)1 IOException (java.io.IOException)1 Duration (java.time.Duration)1 Optional (java.util.Optional)1 CancellationException (java.util.concurrent.CancellationException)1 HttpEntity (org.apache.http.HttpEntity)1 HttpResponse (org.apache.http.HttpResponse)1 HttpRequestBase (org.apache.http.client.methods.HttpRequestBase)1