@@ -7,10 +7,10 @@ import (
7
7
8
8
"github.com/aws/aws-sdk-go/aws"
9
9
"github.com/aws/aws-sdk-go/aws/awserr"
10
+ "github.com/aws/aws-sdk-go/aws/client"
10
11
"github.com/aws/aws-sdk-go/aws/session"
11
12
"github.com/aws/aws-sdk-go/service/dynamodb"
12
13
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface"
13
- "github.com/matryer/try"
14
14
log "github.com/sirupsen/logrus"
15
15
)
16
16
@@ -35,17 +35,19 @@ var ErrSequenceIDNotFound = errors.New("SequenceIDNotFoundForShard")
35
35
36
36
// DynamoCheckpoint implements the Checkpoint interface using DynamoDB as a backend
37
37
type DynamoCheckpoint struct {
38
- TableName string
39
- LeaseDuration int
40
- svc dynamodbiface.DynamoDBAPI
41
- Retries int
38
+ TableName string
39
+ LeaseDuration int
40
+ Retries int
41
+ svc dynamodbiface.DynamoDBAPI
42
+ skipTableCheck bool
42
43
}
43
44
44
45
// Init initialises the DynamoDB Checkpoint
45
46
func (checkpointer * DynamoCheckpoint ) Init () error {
46
47
log .Debug ("Creating DynamoDB session" )
47
48
session , err := session .NewSessionWithOptions (
48
49
session.Options {
50
+ Config : aws.Config {Retryer : client.DefaultRetryer {NumMaxRetries : checkpointer .Retries }},
49
51
SharedConfigState : session .SharedConfigEnable ,
50
52
},
51
53
)
@@ -54,7 +56,8 @@ func (checkpointer *DynamoCheckpoint) Init() error {
54
56
}
55
57
56
58
if endpoint := os .Getenv ("DYNAMODB_ENDPOINT" ); endpoint != "" {
57
- session .Config .Endpoint = aws .String (endpoint )
59
+ log .Infof ("Using dynamodb endpoint from environment %s" , endpoint )
60
+ session .Config .Endpoint = & endpoint
58
61
}
59
62
60
63
checkpointer .svc = dynamodb .New (session )
@@ -63,7 +66,7 @@ func (checkpointer *DynamoCheckpoint) Init() error {
63
66
checkpointer .LeaseDuration = defaultLeaseDuration
64
67
}
65
68
66
- if ! checkpointer .doesTableExist () {
69
+ if ! checkpointer .skipTableCheck && ! checkpointer . doesTableExist () {
67
70
return checkpointer .createTable ()
68
71
}
69
72
return nil
@@ -84,6 +87,14 @@ func (checkpointer *DynamoCheckpoint) GetLease(shard *shardStatus, newAssignTo s
84
87
var expressionAttributeValues map [string ]* dynamodb.AttributeValue
85
88
if ! leaseTimeoutOk || ! assignedToOk {
86
89
conditionalExpression = "attribute_not_exists(AssignedTo)"
90
+ if shard .Checkpoint != "" {
91
+ conditionalExpression = conditionalExpression + " AND SequenceID = :id"
92
+ expressionAttributeValues = map [string ]* dynamodb.AttributeValue {
93
+ ":id" : {
94
+ S : & shard .Checkpoint ,
95
+ },
96
+ }
97
+ }
87
98
} else {
88
99
assignedTo := * assignedVar .S
89
100
leaseTimeout := * leaseVar .S
@@ -108,6 +119,12 @@ func (checkpointer *DynamoCheckpoint) GetLease(shard *shardStatus, newAssignTo s
108
119
S : & leaseTimeout ,
109
120
},
110
121
}
122
+ if shard .Checkpoint != "" {
123
+ conditionalExpression = conditionalExpression + " AND SequenceID = :sid"
124
+ expressionAttributeValues [":sid" ] = & dynamodb.AttributeValue {
125
+ S : & shard .Checkpoint ,
126
+ }
127
+ }
111
128
}
112
129
113
130
marshalledCheckpoint := map [string ]* dynamodb.AttributeValue {
@@ -122,6 +139,10 @@ func (checkpointer *DynamoCheckpoint) GetLease(shard *shardStatus, newAssignTo s
122
139
},
123
140
}
124
141
142
+ if shard .Checkpoint != "" {
143
+ marshalledCheckpoint ["SequenceID" ] = & dynamodb.AttributeValue {S : & shard .Checkpoint }
144
+ }
145
+
125
146
if shard .Checkpoint != "" {
126
147
marshalledCheckpoint ["Checkpoint" ] = & dynamodb.AttributeValue {
127
148
S : & shard .Checkpoint ,
@@ -229,51 +250,26 @@ func (checkpointer *DynamoCheckpoint) saveItem(item map[string]*dynamodb.Attribu
229
250
230
251
func (checkpointer * DynamoCheckpoint ) conditionalUpdate (conditionExpression string , expressionAttributeValues map [string ]* dynamodb.AttributeValue , item map [string ]* dynamodb.AttributeValue ) error {
231
252
return checkpointer .putItem (& dynamodb.PutItemInput {
232
- ConditionExpression : aws .String (conditionExpression ),
233
- TableName : aws .String (checkpointer .TableName ),
234
- Item : item ,
253
+ ConditionExpression : aws .String (conditionExpression ),
254
+ TableName : aws .String (checkpointer .TableName ),
255
+ Item : item ,
235
256
ExpressionAttributeValues : expressionAttributeValues ,
236
257
})
237
258
}
238
259
239
260
func (checkpointer * DynamoCheckpoint ) putItem (input * dynamodb.PutItemInput ) error {
240
- return try .Do (func (attempt int ) (bool , error ) {
241
- _ , err := checkpointer .svc .PutItem (input )
242
- if awsErr , ok := err .(awserr.Error ); ok {
243
- if awsErr .Code () == dynamodb .ErrCodeProvisionedThroughputExceededException ||
244
- awsErr .Code () == dynamodb .ErrCodeInternalServerError &&
245
- attempt < checkpointer .Retries {
246
- // Backoff time as recommended by https://docs.aws.amazon.com/general/latest/gr/api-retries.html
247
- time .Sleep (time .Duration (2 ^ attempt * 100 ) * time .Millisecond )
248
- return true , err
249
- }
250
- }
251
- return false , err
252
- })
261
+ _ , err := checkpointer .svc .PutItem (input )
262
+ return err
253
263
}
254
264
255
265
func (checkpointer * DynamoCheckpoint ) getItem (shardID string ) (map [string ]* dynamodb.AttributeValue , error ) {
256
- var item * dynamodb.GetItemOutput
257
- err := try .Do (func (attempt int ) (bool , error ) {
258
- var err error
259
- item , err = checkpointer .svc .GetItem (& dynamodb.GetItemInput {
260
- TableName : aws .String (checkpointer .TableName ),
261
- Key : map [string ]* dynamodb.AttributeValue {
262
- "ShardID" : {
263
- S : aws .String (shardID ),
264
- },
266
+ item , err := checkpointer .svc .GetItem (& dynamodb.GetItemInput {
267
+ TableName : aws .String (checkpointer .TableName ),
268
+ Key : map [string ]* dynamodb.AttributeValue {
269
+ "ShardID" : {
270
+ S : aws .String (shardID ),
265
271
},
266
- })
267
- if awsErr , ok := err .(awserr.Error ); ok {
268
- if awsErr .Code () == dynamodb .ErrCodeProvisionedThroughputExceededException ||
269
- awsErr .Code () == dynamodb .ErrCodeInternalServerError &&
270
- attempt < checkpointer .Retries {
271
- // Backoff time as recommended by https://docs.aws.amazon.com/general/latest/gr/api-retries.html
272
- time .Sleep (time .Duration (2 ^ attempt * 100 ) * time .Millisecond )
273
- return true , err
274
- }
275
- }
276
- return false , err
272
+ },
277
273
})
278
274
return item .Item , err
279
275
}
0 commit comments