user3089927
user3089927

Reputation: 3895

Getting Throttling Exception on AWS CLI calls as ThrottlingException error

I was trying to explore a new AWS service named Workspaces through AWS CLI and it seems to have the ability to cater 1 request/sec. When I try to hit multiple times simultaneously, it throws ThrottlingException error. Since workspaces is not in boto package as of yet so I am using CLI in python by subprocess calls.

    def describe_workspaces():
        process=subprocess.Popen(access_endpoint.split(), stdout=subprocess.PIPE)
        output=process.communicate()[0]

So, if I call this function >=1/sec, I will have ThrottlingException. How to handle that? And there will be multiple users calling this function simultaneously.

I was thinking of doing batching and async calls but how to fit in this architecture?

Upvotes: 5

Views: 12491

Answers (1)

Abdullah Khawer
Abdullah Khawer

Reputation: 5678

New Solution:

You can resolve this using Config from botocore.config provided by Boto3, which is an AWS SDK in Python, by specifying retry configuration as shown below in the code snippet:

import boto3 
from botocore.config import Config

def describe_workspaces():
    workspaces_client = boto3.client('workspaces', config=Config(connect_timeout=5, read_timeout=60, retries={'max_attempts': 5}))
    return workspaces_client.describe_workspaces()

References:


Old Solution:

You can resolve this using Boto3, which is an AWS SDK in Python, by adding an exception handling for ThrottlingException and retrying as shown below in the code snippet:

import boto3
from botocore.exceptions import ClientError

def describe_workspaces(tries=1):
    try:
        return boto3.client('workspaces').describe_workspaces()
    except ClientError as exception_obj:
        if exception_obj.response['Error']['Code'] == 'ThrottlingException':
            if tries <= 3:
                print("Throttling Exception Occured.")
                print("Retrying.....")
                print("Attempt No.: " + str(tries))
                time.sleep(3*tries)
                return describe_workspaces(tries + 1)
            else:
                print("Attempted 3 Times But No Success.")
                print("Raising Exception.....")
                raise
        else:
            raise

You can create an AWS client outside the function and can modify the logic as required.

You can handle ThrottlingException via AWS CLI as well but it would make more sense if you write some Bash/Shell script instead of a Python script. For Python, Boto3 is recommended.

For more details, check out the following: AWS Workspaces APIs


Generic Old Solution:

If your code has multiple (more than one) AWS client calls and you don't want to add the same code for ThrottlingException handling and retrying again and again to each call in order to achieve reusability (DRY; Don't repeat yourself) and avoid unnecessary code repetition, you can use the following code snippet:

import time
import boto3
from botocore.exceptions import ClientError

def generic_aws_client_method(client, method_name, method_arguments, tries=1):
    """Generic AWS client method with throttling exception handling"""
    try:
        client_method = getattr(client, method_name)
        return client_method(**method_arguments)
    except ClientError as exception_obj:
        if exception_obj.response['Error']['Code'] == 'ThrottlingException':
            if tries <= 3:
                print("Throttling Exception Occured.")
                print("Retrying.....")
                print("Attempt No.: " + str(tries))
                time.sleep(3*tries)
                return generic_aws_client_method(
                    client,
                    method_name,
                    method_arguments,
                    tries + 1
                )
            else:
                print("Attempted 3 Times But No Success.")
                print("Raising Exception.....")
                raise
        else:
            raise

Below you can find some examples on how to use it:

# AWS clients for AWS S3 and AWS SSM respectively
s3_client = boto3.client('s3')
ssm_client = boto3.client('ssm')

# Example 1: With multiple method arguments
mapping = {'Name': '/prod/aws-eks-vpc-id', 'WithDecryption': True}
returned_object = generic_aws_client_method(ssm_client, "get_parameter", mapping)
print(returned_object)

# Example 2: With single method argument
mapping = {'operation_name': 'describe_parameters'}
returned_object = generic_aws_client_method(ssm_client, "get_paginator", mapping)
print(returned_object)

# Example 3: With no method argument
mapping = {}
returned_object = generic_aws_client_method(s3_client, "list_buckets", mapping)
print(returned_object)

Testing ThrottlingException Handling:

In order to test the ThrottlingException handling in the above code snippets, use the following code snippet to raise a custom ClientError by yourself:

raise ClientError(
    {'Error': {'Code': 'ThrottlingException', 'Message': 'Rate exceeded'}},
    'generic_aws_client_method'
)

Upvotes: 10

Related Questions