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.
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;

import java.io.*;

public class CmkDecrypt {

    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 int 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 = "xxxxx";
        String accessKeySecret = "xxxxxx";
        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) {
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}