All Products
Search
Document Center

Key Management Service:Retry requests with exponential backoff

Last Updated:Feb 27, 2026

API calls to Key Management Service (KMS) can occasionally fail due to server errors or throttling. This topic describes how to implement exponential backoff to retry failed requests and provides a Java code example.

When to retry

Retry a request when you receive one of the following transient errors:

  • Server errors (5xx): The server encountered an internal problem. For example, HTTP 500 or 503.

  • Throttling: The request was denied because the API call rate exceeded the allowed limit. The error code is Rejected.Throttling.

Do not retry requests that fail due to client errors such as invalid parameters, missing permissions, or incorrect credentials. These errors require you to fix the request before you try again.

Note

Dedicated KMS gateways do not impose an upper limit on API calls. They use the compute and storage resources of the instance to handle as many calls as possible, so throttling errors do not occur with dedicated gateways.

Retry strategies

StrategyHow it worksBest for
Simple retryRetry at fixed intervals within a specified time window.Low call volume, infrequent failures
Exponential backoffDouble the wait time after each consecutive failure, up to a maximum number of retries.Throttling scenarios, high call volume, or when multiple clients compete for the same resource

Exponential backoff is preferred because it progressively reduces pressure on the service. When a request is denied due to throttling, spacing out retries gives the service time to recover and reduces the chance of further throttling within a short period.

SDK auto-retry support

Some Alibaba Cloud SDKs have built-in retry policies. For example, the Alibaba Cloud SDK for .NET lets you configure automatic retries directly. If your SDK does not support automatic retries, implement the exponential backoff approach described in the following sections.

Exponential backoff algorithm

Pseudocode

The following pseudocode shows the core logic. Each retry waits twice as long as the previous one:

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))

With initialDelay = 200 ms, the wait times progress as follows:

RetryWait time
1400 ms
2800 ms
31,600 ms
43,200 ms
56,400 ms

Best practices

Consider the following practices to make your retry logic more robust:

  • Cap the maximum backoff: The formula 2^retries * initialDelay grows without bound. Set a maximum wait time (for example, 30 seconds) so that retries do not stall your application indefinitely.

  • Add jitter: When many clients back off on the same schedule, they can all retry at the same time and trigger another wave of throttling. This is known as the thundering herd problem. Add a small random component to each wait time, such as waitTime + random(0, waitTime / 2), to spread out retries and reduce collisions.

Retryable and non-retryable errors

Not every error warrants a retry. The following table provides guidance on common KMS error categories.

Error typeExampleRetry?Action
ThrottlingRejected.ThrottlingYesRetry with exponential backoff
Server errorHTTP 500, 503YesRetry with exponential backoff
Authentication failureInvalidAccessKeyId.NotFound, SignatureDoesNotMatchNoFix credentials
Authorization failureForbidden.NoPermissionNoGrant the required permissions
Invalid parameterInvalidParameter, MissingParameterNoFix the request parameters
Resource not foundForbidden.KeyNotFoundNoVerify the resource identifier

Java example: retry throttling errors for the Decrypt operation

The following Java code shows how to use exponential backoff to handle Rejected.Throttling errors when you call the Decrypt operation. You can adapt this code to handle server errors such as HTTP 503.

Estimate the number of requests that the client will initiate within a specific period of time. Then, adjust initialDelay and maxRetries based on the estimation result.

Important

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 operations. 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 in your account may be compromised.

In this example, the AccessKey pair is saved in the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables for identity authentication.

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) {
                    }
                }
            }
        }
    }
}

Related information