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

com.aliyuncs.policy.retry.RetryPolicy Maven / Gradle / Ivy

Go to download

Aliyun Open API SDK for Java Copyright (C) Alibaba Cloud Computing All rights reserved. 版权所有 (C)阿里云计算有限公司 http://www.aliyun.com

The newest version!
package com.aliyuncs.policy.retry;

import com.aliyuncs.exceptions.ThrottlingException;
import com.aliyuncs.policy.cache.ThrottlingPool;
import com.aliyuncs.policy.retry.backoff.BackoffStrategy;
import com.aliyuncs.policy.retry.backoff.EqualJitterBackoffStrategy;
import com.aliyuncs.policy.retry.conditions.ExceptionsCondition;
import com.aliyuncs.policy.retry.conditions.HeadersCondition;
import com.aliyuncs.policy.retry.conditions.RetryCondition;
import com.aliyuncs.policy.retry.conditions.StatusCodeCondition;

import java.text.SimpleDateFormat;
import java.util.*;

public final class RetryPolicy {
    private final int maxNumberOfRetries;
    private final int maxDelayTimeMillis;
    private final BackoffStrategy backoffStrategy;
    private final Set retryConditions;
    private final Set throttlingConditions;
    private final Boolean enableAliyunThrottlingControl;

    private RetryPolicy(BuilderImpl builder) {
        this.maxNumberOfRetries = builder.maxNumberOfRetries;
        this.maxDelayTimeMillis = builder.maxDelayTimeMillis;
        this.backoffStrategy = builder.backoffStrategy;
        this.retryConditions = builder.retryConditions;
        this.throttlingConditions = builder.throttlingConditions;
        this.enableAliyunThrottlingControl = builder.enableAliyunThrottlingControl;
    }

    /**
     * Use default retry policy
     *
     * @param enableAliyunThrottlingControl use or not use aliyun gateway throttling
     * @return retryPolicy
     */
    public static RetryPolicy defaultRetryPolicy(Boolean enableAliyunThrottlingControl) {
        return builder().enableAliyunThrottlingControl(enableAliyunThrottlingControl).build();
    }

    public static RetryPolicy none() {
        return builder()
                .maxNumberOfRetries(0)
                .build();
    }

    public Boolean shouldRetry(RetryPolicyContext context) {
        if (context.retriesAttempted() > maxNumberOfRetries) {
            return false;
        }
        if (throttlingConditions != null && !throttlingConditions.isEmpty()) {
            for (RetryCondition throttlingCondition : throttlingConditions) {
                if (throttlingCondition.meetState(context)) {
                    if (throttlingCondition.escapeTime(context) <= RetryUtil.DEFAULT_ESCAPE_TIME) {
                        return false;
                    }
                    if (enableAliyunThrottlingControl) {
                        long current = System.currentTimeMillis();
                        int escapeTime = throttlingCondition.escapeTime(context);
                        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
                        String endTime = df.format(new Date(current + escapeTime));
                        ThrottlingPool.put(context.coordinate(), endTime, escapeTime);
                        if (context.exception() == null || !ThrottlingException.class.isAssignableFrom(context.exception().getClass())) {
                            context.updateException(new ThrottlingException("SDK.TriggerThrottlingPolicy",
                                    "Client triggered throttling policy, server cannot be accessed before " + endTime
                                            + (context.exception() != null ? ". Error message: \n" + context.exception().getMessage() : "."), context.exception()));
                        }
                    }
                }
            }
        }
        if (getBackoffDelay(context) > maxDelayTimeMillis) {
            return false;
        }
        if (retryConditions != null && !retryConditions.isEmpty()) {
            for (RetryCondition retryCondition : retryConditions) {
                if (retryCondition.meetState(context)) {
                    return true;
                }
            }
        }
        return context.retriesAttempted() == RetryUtil.FIRST_ATTEMPTED;
    }

    public int getBackoffDelay(RetryPolicyContext context) {
        if (context.retriesAttempted() == RetryUtil.FIRST_ATTEMPTED) {
            if (ThrottlingPool.get(context.coordinate()) != null) {
                long current = System.currentTimeMillis();
                int escapeTime = ThrottlingPool.getExpire(context.coordinate());
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
                String endTime = df.format(new Date(current + escapeTime));
                if (context.exception() == null || !ThrottlingException.class.isAssignableFrom(context.exception().getClass())) {
                    context.updateException(new ThrottlingException("SDK.TriggerThrottlingPolicy",
                            "Client triggered throttling policy, server cannot be accessed before " + endTime
                                    + (context.exception() != null ? ". Error message: \n" + context.exception().getMessage() : "."), context.exception()));
                }
                return escapeTime;
            } else {
                return RetryUtil.DEFAULT_ESCAPE_TIME;
            }
        }
        int delayTimeMillis = this.backoffStrategy.computeDelayBeforeNextRetry(context);
        if (throttlingConditions != null && !throttlingConditions.isEmpty()) {
            for (RetryCondition throttlingCondition : throttlingConditions) {
                if (throttlingCondition.meetState(context)) {
                    delayTimeMillis = Math.max(delayTimeMillis, throttlingCondition.escapeTime(context));
                }
            }
        }
        return delayTimeMillis;
    }

    public static Builder builder() {
        return new BuilderImpl();
    }

    public int maxNumberOfRetries() {
        return maxNumberOfRetries;
    }

    public int maxDelayTimeMillis() {
        return maxDelayTimeMillis;
    }

    public BackoffStrategy backoffStrategy() {
        return backoffStrategy;
    }

    public Set retryConditions() {
        return retryConditions;
    }

    public Set throttlingConditions() {
        return throttlingConditions;
    }


    public Boolean enableAliyunThrottlingControl() {
        return enableAliyunThrottlingControl;
    }

    public Builder toBuilder() {
        return builder()
                .maxNumberOfRetries(maxNumberOfRetries)
                .maxDelayTimeMillis(maxDelayTimeMillis)
                .backoffStrategy(backoffStrategy)
                .retryConditions(retryConditions)
                .throttlingConditions(throttlingConditions)
                .enableAliyunThrottlingControl(enableAliyunThrottlingControl);
    }

    public interface Builder {

        Builder maxNumberOfRetries(int numRetries);

        Builder maxDelayTimeMillis(int delayTime);

        Builder backoffStrategy(BackoffStrategy backoffStrategy);

        Builder retryConditions(Set retryConditions);

        Builder throttlingConditions(Set throttlingConditions);

        Builder enableAliyunThrottlingControl(Boolean enableThrottlingControl);

        RetryPolicy build();
    }

    public static final class BuilderImpl implements Builder {
        private int maxNumberOfRetries;
        private int maxDelayTimeMillis;
        private BackoffStrategy backoffStrategy;
        private Set retryConditions = new HashSet();
        private Set throttlingConditions = new HashSet();
        private Boolean enableAliyunThrottlingControl = false;
        private static RetryCondition aliyunThrottlingCondition = HeadersCondition.create(RetryUtil.THROTTLING_PATTERNS);

        private BuilderImpl() {
            this.maxNumberOfRetries = RetryUtil.DEFAULT_MAX_RETRIES;
            this.maxDelayTimeMillis = RetryUtil.MAX_BACKOFF;
            this.backoffStrategy = new EqualJitterBackoffStrategy(RetryUtil.BASE_DELAY, this.maxDelayTimeMillis, new Random());
            this.retryConditions.add(ExceptionsCondition.create(RetryUtil.RETRYABLE_EXCEPTIONS));
            this.retryConditions.add(StatusCodeCondition.create(RetryUtil.RETRYABLE_STATUS_CODES));
        }

        @Override
        public Builder maxNumberOfRetries(int maxNumberOfRetries) {
            this.maxNumberOfRetries = maxNumberOfRetries;
            return this;
        }

        @Override
        public Builder maxDelayTimeMillis(int maxDelayTimeMillis) {
            this.maxDelayTimeMillis = maxDelayTimeMillis;
            return this;
        }

        @Override
        public Builder backoffStrategy(BackoffStrategy backoffStrategy) {
            this.backoffStrategy = backoffStrategy;
            return this;
        }

        @Override
        public Builder retryConditions(Set retryConditions) {
            this.retryConditions = retryConditions;
            return this;
        }

        public Builder retryConditions(RetryCondition... retryCondition) {
            this.retryConditions = new HashSet(Arrays.asList(retryCondition));
            return this;
        }

        @Override
        public Builder throttlingConditions(Set throttlingConditions) {
            this.throttlingConditions = throttlingConditions;
            return this;
        }

        public Builder throttlingConditions(RetryCondition... throttlingCondition) {
            this.throttlingConditions = new HashSet(Arrays.asList(throttlingCondition));
            return this;
        }

        @Override
        public Builder enableAliyunThrottlingControl(Boolean enableAliyunThrottlingControl) {
            this.enableAliyunThrottlingControl = enableAliyunThrottlingControl;
            if (this.enableAliyunThrottlingControl) {
                if (!this.throttlingConditions.contains(aliyunThrottlingCondition)) {
                    this.throttlingConditions.add(aliyunThrottlingCondition);
                }
            } else {
                if (this.throttlingConditions.contains(aliyunThrottlingCondition)) {
                    this.throttlingConditions.remove(aliyunThrottlingCondition);
                }
            }
            return this;
        }

        @Override
        public RetryPolicy build() {
            return new RetryPolicy(this);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy