When you call KMS APIs, errors may occasionally be returned. This topic describes how to use exponential backoff to retry request errors.
Background
When you call a service API, an error may occur at a certain point. In this case, you can retry the request in your application.
Some Alibaba Cloud SDKs support automatic retries through configuration. For example, the Alibaba Cloud SDK for .NET allows you to configure retry policies. When automatic retries are not applicable, you can use the retry method described in this topic.
Retry strategies
If a request fails due to a server error (5xx) or a throttling error, retry the request by using the following retry strategies:
-
Simple retry.
For example, retry once per second for 10 seconds.
-
Exponential backoff.
For consecutive error responses, the retry wait interval becomes increasingly longer. You must retry based on the maximum delay interval and the maximum number of retries. Exponential backoff can prevent continuous conflicts during retries. For example, when requests exceed the throttling quota within a short period of time, exponential backoff can effectively avoid continuous throttling errors.
Dedicated KMS gateways do not impose an upper limit on the number of API calls. Instead, they use a best-effort approach to maximize the use of instance compute and storage resources to process API requests. Therefore, throttling errors do not occur.
Pseudocode for exponential backoff
The following pseudocode shows how to retry an operation by using incremental delays.
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 exponential backoff to handle KMS throttling
The following Java example shows how to use exponential backoff to handle throttling errors when KMS calls the Decrypt operation.
-
You can make simple modifications to retry specific types of server errors, such as HTTP 503.
-
You can estimate the number of requests that the client sends within a specific period of time and adjust the initial delay (
initialDelay) and the number of retries (maxRetries).
An AccessKey pair for an Alibaba Cloud account has permissions for all API operations. We recommend that you use a RAM user to call API operations or perform routine O&M. To prevent security risks, do not hardcode your AccessKey ID and AccessKey Secret in your project code. Hardcoding credentials can lead to leaks that compromise all resources in your account.
This topic provides an example of how to configure the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables for identity authentication.
For more information about how to configure access credentials, see Manage access credentials.
The method for configuring environment variables varies based on the operating system. For more information, see Configure environment variables on Linux, macOS, and Windows.
import com.aliyun.kms20160120.Client;
import com.aliyun.kms20160120.models.DecryptRequest;
import com.aliyun.kms20160120.models.DecryptResponse;
import com.aliyun.tea.*;
import com.aliyun.teautil.models.RuntimeOptions;
import java.nio.charset.StandardCharsets;
public class Main {
private static Client kmsClient;
private static Client kmsClient(String regionId, String accessKeyId, String accessKeySecret) throws Exception {
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
.setAccessKeyId(accessKeyId)
.setAccessKeySecret(accessKeySecret);
config.setRegionId(regionId) ;
return new Client(config);
}
private static String kmsDecrypt(String cipherTextBlob) throws Exception {
DecryptRequest decryptRequest = new DecryptRequest()
// Specify the ciphertext that you want to decrypt.
.setCiphertextBlob(cipherTextBlob);
DecryptResponse response = kmsClient.decryptWithOptions(decryptRequest, new RuntimeOptions());
// Obtain the decrypted plaintext from the response.
String plaintext = response.getBody().getPlaintext();
System.out.println("Ciphertext (Base64): " + cipherTextBlob);
System.out.println("Decrypted Plaintext: " + plaintext);
return plaintext;
}
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) throws Exception {
String regionId = "<region ID>"; // Example: "cn-shanghai"
String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
String cipherTextBlob ="a2V5LXNoaDY4M**********w=";
int maxRetries = 5;
kmsClient = kmsClient(regionId, accessKeyId, accessKeySecret);
for (int i = 0; i < maxRetries; i++) {
try {
String plainText = kmsDecrypt(cipherTextBlob);
return;
} catch (Exception e) {
e.printStackTrace();
if (e.getMessage().contains("Rejected.Throttling")) { // Throttled. Retry the request.
try {
Thread.sleep(getWaitTimeExponential(i + 1));
} catch (InterruptedException ignore) {
}
} else {
break; // Not a throttling error. Stop retrying.
}
}
}
}
}