From 7718cd194c945f8a6a5785ad86d12125ea29ab6d Mon Sep 17 00:00:00 2001 From: John Ewart Date: Wed, 24 Jun 2015 07:23:16 -0700 Subject: [PATCH] Support backing off a bit when throttling / limit-exceeded exceptions happen --- .../aws/resource_aws_dynamodb_table.go | 44 ++++++++++++++++--- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/builtin/providers/aws/resource_aws_dynamodb_table.go b/builtin/providers/aws/resource_aws_dynamodb_table.go index 163d14d8d..b4ca3810e 100644 --- a/builtin/providers/aws/resource_aws_dynamodb_table.go +++ b/builtin/providers/aws/resource_aws_dynamodb_table.go @@ -9,10 +9,20 @@ import ( "github.com/hashicorp/terraform/helper/schema" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/dynamodb" "github.com/hashicorp/terraform/helper/hashcode" ) +// Number of times to retry if a throttling-related exception occurs +const DYNAMODB_MAX_THROTTLE_RETRIES = 5 + +// How long to sleep when a throttle-event happens +const DYNAMODB_THROTTLE_SLEEP = 5 * time.Second + +// How long to sleep if a limit-exceeded event happens +const DYNAMODB_LIMIT_EXCEEDED_SLEEP = 10 * time.Second + // A number of these are marked as computed because if you don't // provide a value, DynamoDB will provide you with defaults (which are the // default values specified below) @@ -249,15 +259,35 @@ func resourceAwsDynamoDbTableCreate(d *schema.ResourceData, meta interface{}) er req.GlobalSecondaryIndexes = globalSecondaryIndexes } - output, err := dynamodbconn.CreateTable(req) - if err != nil { - return fmt.Errorf("Error creating DynamoDB table: %s", err) + attemptCount := 1 + for attemptCount <= DYNAMODB_MAX_THROTTLE_RETRIES { + output, err := dynamodbconn.CreateTable(req) + if err != nil { + if awsErr, ok := err.(awserr.Error); ok { + if awsErr.Code() == "ThrottlingException" { + log.Printf("[DEBUG] Attempt %d/%d: Sleeping for a bit to throttle back create request", attemptCount, DYNAMODB_MAX_THROTTLE_RETRIES) + time.Sleep(DYNAMODB_THROTTLE_SLEEP) + attemptCount += 1 + } else if awsErr.Code() == "LimitExceededException" { + log.Printf("[DEBUG] Limit on creation hit, sleeping for a bit") + time.Sleep(DYNAMODB_LIMIT_EXCEEDED_SLEEP) + } else { + // Some other non-retryable exception occurred + return fmt.Errorf("AWS Error creating DynamoDB table: %s", err) + } + } else { + // Non-AWS exception occurred, give up + return fmt.Errorf("Error creating DynamoDB table: %s", err) + } + } else { + // No error, set ID and return + d.SetId(*output.TableDescription.TableName) + return nil + } } - d.SetId(*output.TableDescription.TableName) - - // Creation complete, nothing to re-read - return nil + // Too many throttling events occurred, give up + return fmt.Errorf("Unable to create DynamoDB table '%s' after %d attempts", name, attemptCount) } func resourceAwsDynamoDbTableUpdate(d *schema.ResourceData, meta interface{}) error {