All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.deepsense.neptune.clientlibrary.services.apiservice.retries.IncreasingTimeoutsRequestRetryStrategy Maven / Gradle / Ivy

There is a newer version: 1.6.1
Show newest version
/**
 * Copyright (c) 2016, CodiLime Inc.
 */

package io.deepsense.neptune.clientlibrary.services.apiservice.retries;

import io.deepsense.neptune.apiclient.ApiException;
import io.deepsense.neptune.clientlibrary.config.internal.RequestRetryConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.ThreadLocalRandom;

public class IncreasingTimeoutsRequestRetryStrategy implements RequestRetryStrategy {

    private static final Logger logger = LoggerFactory.getLogger(IncreasingTimeoutsRequestRetryStrategy.class);

    // Response code 0 is returned by Swagger on various types of connection failure.
    private static final Collection responseCodesToIgnore = Arrays.asList(0, 500, 502, 503, 504);

    private final long retryTimeoutCap;

    private int attemptCounter = 0;

    public IncreasingTimeoutsRequestRetryStrategy(RequestRetryConfiguration configuration) {
        this.retryTimeoutCap = configuration.getMaxTimeoutBetweenRequestsInMillis();
    }

    @Override
    public  RequestRetryOutcome retryRequest(Request request) throws ApiException {
        incrementAttemptCounter();
        if (previousRequestFailed()) {
            System.out.println("Connection lost. Retrying...");
        }
        try {
            T value = request.send();
            return requestSucceeded(value);
        } catch (ApiException exc) {
            return handleApiException(exc);
        } catch (Exception exc) {
            return requestFailed();
        }
    }

    private  RequestRetryOutcome handleApiException(ApiException exc) throws ApiException {
        if (responseCodesToIgnore.contains(exc.getCode())) {
            return requestFailed();
        } else {
            clearAttemptCounter();
            throw exc;
        }
    }

    private  RequestRetryOutcome requestSucceeded(T value) {

        Runnable postRequestAction;

        if (previousRequestFailed()) {
            postRequestAction = IncreasingTimeoutsRequestRetryStrategy.this::onReconnect;
        } else {
            postRequestAction = null;
        }

        clearAttemptCounter();
        return new RequestRetryOutcome<>(true, value, postRequestAction);
    }

    private  RequestRetryOutcome requestFailed() {
        return new RequestRetryOutcome<>(false, null, this::sleep);
    }

    private void onReconnect() {
        System.out.println("Connection restored!");
    }

    private void sleep() {
        try {
            long maxSleepTime = Math.min(powerOf2(attemptCounter - 1), retryTimeoutCap);
            long sleepTime = ThreadLocalRandom.current().nextLong(0, maxSleepTime + 1);
            logger.debug("Attempt #%d to make a request failed. Next try in %d ms.", attemptCounter, sleepTime);
            Thread.sleep(sleepTime);
        } catch (InterruptedException ignored) {
            logger.debug("Sleep in request retry loop was interrupted!");
        }
    }

    private boolean previousRequestFailed() {
        return attemptCounter > 1;
    }

    private void incrementAttemptCounter() {
        attemptCounter++;
    }

    private void clearAttemptCounter() {
        attemptCounter = 0;
    }

    private static long powerOf2(int exponent) {
        return 1L << exponent;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy