All Products
Search
Document Center

Key Management Service:Use the exponential backoff method to retry requests

Last Updated:Jun 15, 2023

When you call API operations of Key Management Service (KMS), errors are returned sometimes. This topic describes how to use the exponential backoff method to retry the failed requests.

Background information

If an error occurs when you call an API operation, you can retry the request in the application.

Some Alibaba Cloud SDKs support automatic retries. For example, you can configure automatic retry policies for Alibaba Cloud SDKs for .NET. If your SDK does not support automatic retries, you can use the method described in this topic.

Retry methods

If a server error (5xx) is returned or your request is denied due to throttling, you can use one of the following methods:

  • Simple retry

    Retry a request at fixed intervals within a specified period of time.

  • Exponential backoff

    For consecutive errors, increase the waiting time between retries exponentially based on a maximum backoff time and a maximum number of retries. This method helps prevent constant errors returned during the retry process. For example, you can use this method to retry a request that was denied due to throttling. This reduces the number of throttling errors returned within a short period of time.

Pseudocode for exponential backoff

The following pseudocode demonstrates how to achieve exponential increase of waiting time between retries:

initialDelay = 200
retries = 0

DO
    wait for (2^retries * initialDelay) milliseconds

    status = CallSomeAPI()

    IF status == SUCCESS
        retry = false // Succeeded, stop calling the API again.
    ELSE IF status = THROTTLED || status == SERVER_NOT_READY
        retry = true  // Failed because of throttling or server busy, try again.
    ELSE
        retry = false // Some other error occurred, stop calling the API again.
    END IF

    retries = retries + 1

WHILE (retry AND (retries < MAX_RETRIES))

Use the exponential backoff method to process throttling errors in KMS

The following Java code demonstrates how to use the exponential backoff method to process the throttling errors returned when the Decrypt operation is called.

  • You can make simple modifications to the code to process certain server errors, such as HTTP error 503.

  • You can estimate the number of requests that the client will initiate within a specific period of time. Then, adjust the initial delay (initialDelay) and maximum number of retries (maxRetries) in the code based on the estimation result.

Note

The AccessKey pair of an Alibaba Cloud account has permissions on all API operations. Using the AccessKey pair to perform operations is a high-risk operation. We recommend that you use a RAM user to call API operations or perform routine O&M. We recommend that you do not save the AccessKey ID and AccessKey secret in your project code. Otherwise, the AccessKey pair may be leaked and the security of all resources within your account may be compromised.

In this example, the AccessKey pair is saved in ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables to implement identity authentication. For more information about how to configure authentication information, see Credentials.

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.FormatType;
import com.aliyuncs.http.HttpClientConfig;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.kms.model.v20160120.DecryptRequest;
import com.aliyuncs.kms.model.v20160120.DecryptResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;

public class CmkDecrypt {
    private static DefaultAcsClient kmsClient;

    private static DefaultAcsClient kmsClient(String regionId, String accessKeyId, String accessKeySecret) {
        IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
        HttpClientConfig clientConfig = HttpClientConfig.getDefault();
        profile.setHttpClientConfig(clientConfig);

        return new DefaultAcsClient(profile);
    }

    private static String kmsDecrypt(String cipherTextBlob) throws ClientException {
        final DecryptRequest request = new DecryptRequest();
        request.setSysProtocol(ProtocolType.HTTPS);
        request.setAcceptFormat(FormatType.JSON);
        request.setSysMethod(MethodType.POST);
        request.setCiphertextBlob(cipherTextBlob);
        DecryptResponse response = kmsClient.getAcsResponse(request);
        return response.getPlaintext();
    }

    public static long getWaitTimeExponential(int retryCount) {
        final long initialDelay = 200L;
        long waitTime = ((long) Math.pow(2, retryCount) * initialDelay);
        return waitTime;
    }

    public static void main(String[] args) {
        String regionId = "xxxxx"; //"cn-shanghai"
        String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
        String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
        String cipherTextBlob = "xxxxxx";

        int maxRetries = 5;

        kmsClient = kmsClient(regionId, accessKeyId, accessKeySecret);

        for (int i = 0; i < maxRetries; i++) {
            try {
                String plainText = kmsDecrypt(cipherTextBlob);
                return;
            } catch (ClientException e) {
                if (e.getErrCode().contains("Rejected.Throttling")) {//need retry
                    try {
                        Thread.sleep(getWaitTimeExponential(i + 1));
                    } catch (InterruptedException ignore) {
                    }
                }
            }
        }
    }
}