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

io.sphere.sdk.client.retry.RetryableSphereClientBuilder Maven / Gradle / Ivy

The newest version!
package io.sphere.sdk.client.retry;

import io.sphere.sdk.client.QueueSphereClientDecorator;
import io.sphere.sdk.client.RetrySphereClientDecorator;
import io.sphere.sdk.client.SphereAccessTokenSupplier;
import io.sphere.sdk.client.SphereClient;
import io.sphere.sdk.client.SphereClientConfig;
import io.sphere.sdk.http.HttpClient;
import io.sphere.sdk.models.Base;
import io.sphere.sdk.retry.RetryAction;
import io.sphere.sdk.retry.RetryPredicate;
import io.sphere.sdk.retry.RetryRule;

import javax.annotation.Nonnull;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static java.lang.String.format;

/**
 * To create a Sphere Client with retry logic which computes a exponential backoff time delay in milliseconds.
 * And handle all the configurations for the creation of client.
 */
public final class RetryableSphereClientBuilder extends Base {
    protected static final long DEFAULT_MAX_DELAY = 60000;
    protected static final long DEFAULT_INITIAL_RETRY_DELAY = 200;
    protected static final int DEFAULT_MAX_RETRY_ATTEMPT = 5;
    protected static final int DEFAULT_MAX_PARALLEL_REQUESTS = 20;
    private static final List DEFAULT_STATUS_CODES_TO_RETRY = Arrays.asList(500, 502, 503, 504);

    private final SphereClientConfig sphereClientConfig;
    private final HttpClient httpClient;
    private long maxDelay;
    private long initialRetryDelay;
    private int maxRetryAttempt;
    private int maxParallelRequests;
    private List statusCodesToRetry;

    private RetryableSphereClientBuilder(
            @Nonnull final SphereClientConfig sphereClientConfig,
            @Nonnull final HttpClient httpClient) {

        this.sphereClientConfig = sphereClientConfig;
        this.httpClient = httpClient;
        this.maxDelay = DEFAULT_MAX_DELAY;
        this.initialRetryDelay = DEFAULT_INITIAL_RETRY_DELAY;
        this.maxRetryAttempt = DEFAULT_MAX_RETRY_ATTEMPT;
        this.maxParallelRequests = DEFAULT_MAX_PARALLEL_REQUESTS;
        this.statusCodesToRetry = DEFAULT_STATUS_CODES_TO_RETRY;
    }

    /**
     * Creates a new instance of {@link RetryableSphereClientBuilder} given a {@link SphereClientConfig}
     * responsible for creation of a SphereClient.
     *
     * @param sphereClientConfig the client configuration for the client.
     * @param httpClient         client to execute requests
     * @return the instantiated {@link RetryableSphereClientBuilder}.
     */
    public static RetryableSphereClientBuilder of(
            @Nonnull final SphereClientConfig sphereClientConfig,
            @Nonnull final HttpClient httpClient) {

        return new RetryableSphereClientBuilder(sphereClientConfig, httpClient);
    }

    /**
     * Sets the maxDelay value value in milliseconds.
     *
     * @param maxDelay - build with maxDelay value.
     * @return {@link RetryableSphereClientBuilder} with given maxDelay value.
     */
    public RetryableSphereClientBuilder withMaxDelay(final long maxDelay) {
        this.maxDelay = maxDelay;
        return this;
    }

    /**
     * Sets the initialDelay value in milliseconds.
     *
     * @param initialDelay - build with initialDelay value.
     *                     If initialDelay is equal or greater than maxDelay then, a {@link IllegalArgumentException} will be thrown.
     * @return {@link RetryableSphereClientBuilder} with given initialDelay value.
     */
    public RetryableSphereClientBuilder withInitialDelay(final long initialDelay) {
        if (initialDelay < maxDelay) {
            this.initialRetryDelay = initialDelay;
        } else {
            throw new IllegalArgumentException(
                    format("InitialDelay %s is less than MaxDelay %s.", initialDelay, maxDelay));
        }
        return this;
    }

    /**
     * Sets the Max Retry value, It should be greater than 1 for the Retry attempt.
     *
     * @param maxRetryAttempt - build with maxRetries value.
     *                        If maxRetryAttempt is less than 1 then, a {@link IllegalArgumentException} will be thrown.
     * @return {@link RetryableSphereClientBuilder} with given maxRetries value.
     */
    public RetryableSphereClientBuilder withMaxRetryAttempt(final int maxRetryAttempt) {
        if (maxRetryAttempt > 0) {
            this.maxRetryAttempt = maxRetryAttempt;
        } else {
            throw new IllegalArgumentException(format("MaxRetryAttempt %s cannot be less than 1.", maxRetryAttempt));
        }
        return this;
    }

    /**
     * Sets the Max Parallel Requests value, It should be always positive number.
     *
     * @param maxParallelRequests - build with maxParallelRequests value.
     *                            If maxParallelRequests is less than 1 then, a {@link IllegalArgumentException} will be thrown.
     * @return {@link RetryableSphereClientBuilder} with given maxParallelRequests value.
     */
    public RetryableSphereClientBuilder withMaxParallelRequests(final int maxParallelRequests) {
        if (maxParallelRequests > 0) {
            this.maxParallelRequests = maxParallelRequests;
        } else {
            throw new IllegalArgumentException(
                    format("MaxParallelRequests %s cannot be less than 0", maxParallelRequests));
        }
        return this;
    }

    /**
     * Sets the Retry Error Status Codes.
     *
     * @param statusCodesToRetry - build with retryErrorStatusCodes.
     * @return {@link RetryableSphereClientBuilder} with given retryErrorStatusCodes.
     */
    public RetryableSphereClientBuilder withStatusCodesToRetry(final List statusCodesToRetry) {
        this.statusCodesToRetry = statusCodesToRetry;
        return this;
    }

    /**
     * creates a SphereClient using the class configuration values.
     *
     * @return the instantiated {@link SphereClient}
     */
    public SphereClient build() {
        final SphereClient underlyingClient = createUnderlyingSphereClient(httpClient, sphereClientConfig);
        return decorateSphereClient(underlyingClient, RetryAction.ofExponentialBackoff(maxRetryAttempt, initialRetryDelay, maxDelay), maxParallelRequests);
    }

    private SphereClient createUnderlyingSphereClient(
            @Nonnull final HttpClient httpClient,
            @Nonnull final SphereClientConfig clientConfig) {
        final SphereAccessTokenSupplier tokenSupplier =
                SphereAccessTokenSupplier.ofAutoRefresh(clientConfig, httpClient, false);
        return SphereClient.of(clientConfig, httpClient, tokenSupplier);
    }

    protected SphereClient decorateSphereClient(
            @Nonnull final SphereClient underlyingClient,
            @Nonnull final RetryAction retryAction,
            final int maxParallelRequests) {
        final SphereClient retryClient = withRetry(underlyingClient, retryAction);
        return withLimitedParallelRequests(retryClient, maxParallelRequests);
    }

    private SphereClient withRetry(@Nonnull final SphereClient delegate, final RetryAction retryAction) {
        final RetryPredicate http5xxMatcher = RetryPredicate.ofMatchingStatusCodes(
                errCode -> statusCodesToRetry.stream().anyMatch(i -> i.equals(errCode)));
        final List retryRules = Collections.singletonList(RetryRule.of(http5xxMatcher, retryAction));
        return RetrySphereClientDecorator.of(delegate, retryRules);
    }

    private SphereClient withLimitedParallelRequests(final SphereClient delegate, final int maxParallelRequests) {
        return QueueSphereClientDecorator.of(delegate, maxParallelRequests);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy