Retry mechanism

更新时间:
复制 MD 格式

The Java SDK supports configurable retry policies that let you control which errors trigger retries, set maximum retry counts, and apply exponential backoff.

Note

A retry mechanism and a throttling policy are added. For more information, see Advanced backoff mechanism based on the throttling policy.

The core library aliyun-java-sdk-core V4.6.0 or later supports the retry mechanism and provides an advanced backoff scheme based on the throttling policy. For more information, see Advanced backoff mechanism based on the throttling policy. You must add the following Maven dependency:

<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>4.6.0</version>
</dependency>

Retry mechanism

Disable the retry mechanism

The retry mechanism is disabled by default. To disable it explicitly, set the retry policy to none at the client or request level:

// Specify a retry policy for the client to disable the retry mechanism.
client.setSysRetryPolicy(RetryPolicy.none());

// Specify a retry policy for the request. The retry policy configuration of the request takes precedence over the retry policy configuration of the client.
request.setSysRetryPolicy(RetryPolicy.none());

Retry policies

The SDK supports three types of retry policies:

  1. Specify exceptions.

  2. Specify HTTP status codes.

  3. Specify HTTP response headers.

These three conditions are independent. If any condition is met, the SDK retries the request or stops retrying. You can create policies that trigger retries and policies that restrict them.

The following examples show how to configure policies that trigger or restrict retries:

  • Create a retry policy collection:

    Set<RetryCondition> retryConditions = new HashSet<RetryCondition>();
    
    // Example of conditions
    // Specify status codes to trigger a retry. In the following example, a retry is performed when the status code 500 or 501 is returned.
    Set<Integer> statusCodes = new HashSet<Integer>();
    statusCodes.add(500); // http statusCode
    statusCodes.add(501); // http statusCode
    // Add the status code configuration to the policy that is used to trigger a retry.
    retryConditions.add(StatusCodeCondition.create(statusCodes));
    
    // Specify exceptions to trigger a retry. In the following example, a retry is performed when a SocketTimeoutException or IOException is thrown.
    Set<Class<?  extends Exception>> exceptions = new HashSet<Class<?  extends Exception>>();
    exceptions.add(SocketTimeoutException.class); // exception
    exceptions.add(IOException.class); // exception
    // Add the exception configuration to the policy that is used to trigger a retry.
    retryConditions.add(ExceptionsCondition.create(exceptions));
  • Create a collection of conditions to restrict retries:

    Set<RetryCondition> throttlingConditions = new HashSet<RetryCondition>();
    
    // Example of conditions
    // Specify status codes to restrict a retry. In the following example, a retry is prohibited when the status code 429 is returned.
    Set<Integer> code = new HashSet<Integer>();
    code.add(429); // Specify an HTTP status code to restrict a retry. In this example, a retry is prohibited if the status code 429 is returned.
    // Add the status code configuration to the policy that is used to restrict retires.
    throttlingConditions.add(StatusCodeCondition.create(code));
  • Add conditions to RetryPolicy:

    RetryPolicy retryPolicy = RetryPolicy.builder()
                    .maxNumberOfRetries(3) // The maximum number of retries.
                    .maxDelayTimeMillis(20 * 1000) // The maximum retry interval. Unit: milliseconds. If the specified duration is exceeded, no retries are performed.
                    .retryConditions(retryConditions) // The policy that is used to trigger retries.
                    . .throttlingConditions(throttlingConditions) // The policy that is used to restrict retries.
                    .build();

Retry intervals are calculated by using an exponential backoff algorithm. The EqualJitter algorithm determines the wait time before each retry.

Configure advanced settings of conditions for retries

The following section describes the three built-in condition types in detail.

  1. StatusCodeCondition

    1. Stores a collection of integers. The SDK compares each integer with the returned HTTP status code to determine whether to trigger or restrict retries.

  2. ExceptionsCondition

    1. Stores a collection of exceptions. The SDK compares each exception with the exception thrown during the call to determine whether to trigger or restrict retries.

  3. HeadersCondition

    1. Stores a map with a complex structure. The map key matches the response header key, and the value is evaluated through the Pattern (com.aliyuncs.policy.retry.pattern.Pattern) interface. The pattern checks whether the response header value contains a specific string or equals a given value.

    2. Two patterns are supported: AliyunThrottlingPattern and SimplePattern. AliyunThrottlingPattern applies the throttling policy provided by Alibaba Cloud. For more information, see Advanced backoff mechanism based on the throttling policy. SimplePattern checks whether values are equal.

    3. To customize the Pattern interface, implement the following three methods:

      1. meetState(): returns true when the rule is matched.

      2. `escapeTime()`: returns the escape time in milliseconds. This method applies only to retry restriction policies. If the return value is not -1, retries are paused for the specified duration rather than permanently restricted. The SDK waits until the escape time elapses before retrying. If this value exceeds the maximum retry interval, the request fails immediately.

      3. readFormHeadersContent(String content): parses and assigns a value from the header. You can reuse the SimplePattern implementation directly.

  4. Custom conditions

    1. To create custom conditions, implement the RetryCondition interface with the following two methods:

      1. meetState(RetryPolicyContext var1): evaluates whether the retry condition is met based on the context.

      2. escapeTime(RetryPolicyContext var1): calculates the escape time. This method applies only to restriction policies. For trigger policies, return -1.

Complete sample code

Sample code:

package com.aliyun.sample;

import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.exceptions.ThrottlingException;
import com.aliyuncs.policy.retry.RetryPolicy;
import com.aliyuncs.policy.retry.conditions.ExceptionsCondition;
import com.aliyuncs.policy.retry.conditions.RetryCondition;
import com.aliyuncs.policy.retry.conditions.StatusCodeCondition;
import com.aliyuncs.profile.DefaultProfile;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.HashSet;
import java.util.Set;

public class Sample {
    public static void main(String[] args) {
        // Create and initialize a DefaultAcsClient instance.
        DefaultProfile profile = DefaultProfile.getProfile(
                // The region ID.
                "cn-hangzhou",
                // Obtain the AccessKey ID of the RAM user from an environment variable.
                System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"),
                // Obtain the AccessKey secret of the RAM user from an environment variable.
                System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
        IAcsClient client = new DefaultAcsClient(profile);
        // Configure the retry policy at the client level.
        client.setSysRetryPolicy(RetryPolicy.none());
        // This example uses CommonRequest. The configuration also applies to product-specific SDKs, such as <APIName>Request.
        CommonRequest request = new CommonRequest();
        // Configure the retry policy at the request level. This configuration has a higher priority than the client-level configuration.
        request.setSysRetryPolicy(RetryPolicy.defaultRetryPolicy(true));

        // Configure status codes to trigger retries.
        Set<RetryCondition> retryConditions = new HashSet<RetryCondition>();
        Set<Integer> statusCodes = new HashSet<Integer>();
        statusCodes.add(500); // http statusCode
        statusCodes.add(501); // http statusCode
        retryConditions.add(StatusCodeCondition.create(statusCodes));

        // Configure exceptions to trigger retries.
        Set<Class<? extends Exception>> exceptions = new HashSet<Class<? extends Exception>>();
        exceptions.add(SocketTimeoutException.class); // exception
        exceptions.add(IOException.class); // exception
        retryConditions.add(ExceptionsCondition.create(exceptions));

        // Configure status codes to restrict retries.
        Set<RetryCondition> throttlingConditions = new HashSet<RetryCondition>();
        Set<Integer> code = new HashSet<Integer>();
        code.add(429); // http statusCode, restriction policy. This means a 429 status code restricts retries.
        throttlingConditions.add(StatusCodeCondition.create(code));

        RetryPolicy retryPolicy = RetryPolicy.builder()
                .maxNumberOfRetries(3) // Maximum number of retries.
                .maxDelayTimeMillis(20 * 1000) // Maximum retry interval. No more retries are attempted after this time.
                .retryConditions(retryConditions) // Policy to trigger retries.
                .enableAliyunThrottlingControl(true) // Use the Alibaba Cloud throttling policy for control.
                .throttlingConditions(throttlingConditions) // You can also write your own restriction policy.
                .build();

        try {
            // This example uses CommonRequest. The configuration also applies to product-specific SDKs, such as <APIName>Request.
            CommonResponse response = client.getCommonResponse(request);
            System.out.println(response.getData());
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
            if (ThrottlingException.class.isAssignableFrom(e.getCause().getClass())) {
                // The throttling exception is encapsulated in ClientException.
            }
        }
    }
}