Skip to content

Commit

Permalink
Merge pull request #37 from Clever/dynamo-add-retries
Browse files Browse the repository at this point in the history
Add retries during DynamoDB bucket intialization
  • Loading branch information
Sayan- authored Apr 30, 2020
2 parents d6df64f + 6fcd44a commit 9023cbf
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 5 deletions.
9 changes: 9 additions & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@
[[constraint]]
name = "github.com/aws/aws-sdk-go"
version = "1.29.0"

[[constraint]]
name = "github.com/eapache/go-resiliency"
version = "^1.2.0"
3 changes: 2 additions & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
v1.0.0
v1.1.0
- v1.1.0: add retries during dynamodb bucket initialization
- v1.0.0: added dynamodb backed implementation
33 changes: 29 additions & 4 deletions dynamodb/bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ For additional details please refer to: https://github.com/Clever/leakybucket/tr
package dynamodb

import (
"strings"
"sync"
"time"

Expand All @@ -14,6 +15,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/eapache/go-resiliency/retrier"
)

var _ leakybucket.Bucket = &bucket{}
Expand Down Expand Up @@ -132,10 +134,16 @@ func New(tableName string, s *session.Session, itemTTL time.Duration) (*Storage,
ttl: itemTTL,
}

// fail early if the table doesn't exist or we have any other issues with the DynamoDB API
if _, err := ddb.DescribeTable(&dynamodb.DescribeTableInput{
TableName: aws.String(tableName),
}); err != nil {
// Fail early if the table doesn't exist or we have any other issues with the DynamoDB API
// but guarantee we retry dial timeouts to be tolerant to a networking blip
r := retrier.New(retrier.ExponentialBackoff(5, 1*time.Second), dialTimeoutRetrier{})
err := r.Run(func() error {
_, err := ddb.DescribeTable(&dynamodb.DescribeTableInput{
TableName: aws.String(tableName),
})
return err
})
if err != nil {
return nil, err
}

Expand All @@ -157,3 +165,20 @@ func min(a, b uint) uint {
}
return b
}

// dialTimeoutRetrier classifies errors from DynamoDB API in the form of
// Post https://dynamodb.{region}.amazonaws.com: dial tcp x.x.x.x: i/o timeout
// as retryable errors. This classifier is only used in `New` as we don't want to override the
// consumer's configuration during normal operation
type dialTimeoutRetrier struct{}

var _ retrier.Classifier = dialTimeoutRetrier{}

func (dialTimeoutRetrier) Classify(err error) retrier.Action {
if err == nil {
return retrier.Succeed
} else if strings.Contains(err.Error(), "dial tcp") && strings.Contains(err.Error(), "i/o timeout") {
return retrier.Retry
}
return retrier.Fail
}

0 comments on commit 9023cbf

Please sign in to comment.