com.netflix.spinnaker.orca.pipeline.util.HttpClientUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.netflix.spinnaker.orca.pipeline.util.HttpClientUtils.java

Source

/*
 * Copyright 2017 Netflix, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.netflix.spinnaker.orca.pipeline.util;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import com.google.common.io.CharStreams;
import com.google.common.util.concurrent.Uninterruptibles;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ServiceUnavailableRetryStrategy;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpCoreContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpClientUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtils.class);
    private static final int MAX_RETRIES = 5;
    private static final int RETRY_INTERVAL = 5000;
    private static final int TIMEOUT_MILLIS = 30000;
    private static List<Integer> RETRYABLE_500_HTTP_STATUS_CODES = Arrays.asList(HttpStatus.SC_SERVICE_UNAVAILABLE,
            HttpStatus.SC_INTERNAL_SERVER_ERROR, HttpStatus.SC_GATEWAY_TIMEOUT);

    private static CloseableHttpClient httpClient = httpClientWithServiceUnavailableRetryStrategy();

    private static CloseableHttpClient httpClientWithServiceUnavailableRetryStrategy() {
        HttpClientBuilder httpClientBuilder = HttpClients.custom()
                .setServiceUnavailableRetryStrategy(new ServiceUnavailableRetryStrategy() {
                    @Override
                    public boolean retryRequest(HttpResponse response, int executionCount, HttpContext context) {
                        int statusCode = response.getStatusLine().getStatusCode();
                        HttpUriRequest currentReq = (HttpUriRequest) context
                                .getAttribute(HttpCoreContext.HTTP_REQUEST);
                        LOGGER.info("Response code {} for {}", statusCode, currentReq.getURI());

                        if (statusCode >= HttpStatus.SC_OK && statusCode <= 299) {
                            return false;
                        }

                        boolean shouldRetry = (statusCode == 429
                                || RETRYABLE_500_HTTP_STATUS_CODES.contains(statusCode))
                                && executionCount <= MAX_RETRIES;
                        if (!shouldRetry) {
                            throw new RetryRequestException(String.format("Not retrying %s. Count %d, Max %d",
                                    currentReq.getURI(), executionCount, MAX_RETRIES));
                        }

                        LOGGER.error("Retrying request on response status {}. Count {} Max is {}", statusCode,
                                executionCount, MAX_RETRIES);
                        return true;
                    }

                    @Override
                    public long getRetryInterval() {
                        return RETRY_INTERVAL;
                    }
                });

        httpClientBuilder.setRetryHandler((exception, executionCount, context) -> {
            HttpUriRequest currentReq = (HttpUriRequest) context.getAttribute(HttpCoreContext.HTTP_REQUEST);
            Uninterruptibles.sleepUninterruptibly(RETRY_INTERVAL, TimeUnit.MILLISECONDS);
            LOGGER.info("Encountered network error. Retrying request {},  Count {} Max is {}", currentReq.getURI(),
                    executionCount, MAX_RETRIES);
            return executionCount <= MAX_RETRIES;
        });

        httpClientBuilder.setDefaultRequestConfig(RequestConfig.custom().setConnectionRequestTimeout(TIMEOUT_MILLIS)
                .setConnectTimeout(TIMEOUT_MILLIS).setSocketTimeout(TIMEOUT_MILLIS).build());

        return httpClientBuilder.build();
    }

    public static String httpGetAsString(String url) throws IOException {
        try (CloseableHttpResponse response = httpClient.execute(new HttpGet(url))) {
            try (final Reader reader = new InputStreamReader(response.getEntity().getContent())) {
                return CharStreams.toString(reader);
            }
        }
    }

    static class RetryRequestException extends RuntimeException {
        RetryRequestException(String cause) {
            super(cause);
        }
    }
}