1
1
package aws
2
2
3
3
import (
4
+ "context"
5
+ "errors"
4
6
"log"
5
7
"os"
6
- "strconv"
7
8
"time"
8
9
9
- "github.com/aws/aws-sdk-go/aws"
10
- "github.com/aws/aws-sdk-go/aws/awserr"
11
- "github.com/aws/aws-sdk-go/service/dynamodb"
12
- "github.com/aws/aws-sdk-go/service/dynamodb/expression"
10
+ "github.com/aws/aws-sdk-go-v2/aws"
11
+ "github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
12
+ "github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression"
13
+
14
+ "github.com/aws/aws-sdk-go-v2/service/dynamodb"
15
+ "github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
16
+
17
+ "github.com/aws/smithy-go"
13
18
)
14
19
15
20
const (
@@ -20,30 +25,27 @@ const (
20
25
)
21
26
22
27
type DynamoDbLock struct {
23
- DynamoDb * dynamodb.DynamoDB
28
+ DynamoDb * dynamodb.Client
24
29
}
25
30
26
31
func isResourceNotFoundExceptionError (err error ) bool {
27
32
if err != nil {
28
- aerr , ok := err .(awserr.Error )
29
- if ! ok {
30
- // not aws error
31
- return false
32
- }
33
-
34
- if aerr .Code () == dynamodb .ErrCodeResourceNotFoundException {
35
- // ErrCodeResourceNotFoundException code
36
- return true
33
+ var apiError smithy.APIError
34
+ if errors .As (err , & apiError ) {
35
+ switch apiError .(type ) {
36
+ case * types.ResourceNotFoundException :
37
+ return true
38
+ }
37
39
}
38
40
}
39
41
return false
40
42
}
41
43
42
- func (dynamoDbLock * DynamoDbLock ) waitUntilTableCreated () error {
44
+ func (dynamoDbLock * DynamoDbLock ) waitUntilTableCreated (ctx context. Context ) error {
43
45
input := & dynamodb.DescribeTableInput {
44
46
TableName : aws .String (TABLE_NAME ),
45
47
}
46
- status , err := dynamoDbLock .DynamoDb .DescribeTable (input )
48
+ status , err := dynamoDbLock .DynamoDb .DescribeTable (ctx , input )
47
49
cnt := 0
48
50
49
51
if err != nil {
@@ -52,9 +54,9 @@ func (dynamoDbLock *DynamoDbLock) waitUntilTableCreated() error {
52
54
}
53
55
}
54
56
55
- for * status .Table .TableStatus != "ACTIVE" {
57
+ for status .Table .TableStatus != "ACTIVE" {
56
58
time .Sleep (TableCreationInterval )
57
- status , err = dynamoDbLock .DynamoDb .DescribeTable (input )
59
+ status , err = dynamoDbLock .DynamoDb .DescribeTable (ctx , input )
58
60
if err != nil {
59
61
if ! isResourceNotFoundExceptionError (err ) {
60
62
return err
@@ -72,8 +74,8 @@ func (dynamoDbLock *DynamoDbLock) waitUntilTableCreated() error {
72
74
}
73
75
74
76
// TODO: refactor func to return actual error and fail on callers
75
- func (dynamoDbLock * DynamoDbLock ) createTableIfNotExists () error {
76
- _ , err := dynamoDbLock .DynamoDb .DescribeTable (& dynamodb.DescribeTableInput {
77
+ func (dynamoDbLock * DynamoDbLock ) createTableIfNotExists (ctx context. Context ) error {
78
+ _ , err := dynamoDbLock .DynamoDb .DescribeTable (ctx , & dynamodb.DescribeTableInput {
77
79
TableName : aws .String (TABLE_NAME ),
78
80
})
79
81
@@ -84,38 +86,39 @@ func (dynamoDbLock *DynamoDbLock) createTableIfNotExists() error {
84
86
}
85
87
86
88
createtbl_input := & dynamodb.CreateTableInput {
87
- AttributeDefinitions : []* dynamodb.AttributeDefinition {
89
+
90
+ AttributeDefinitions : []types.AttributeDefinition {
88
91
{
89
92
AttributeName : aws .String ("PK" ),
90
- AttributeType : aws . String ( "S" ) ,
93
+ AttributeType : types . ScalarAttributeTypeS ,
91
94
},
92
95
{
93
96
AttributeName : aws .String ("SK" ),
94
- AttributeType : aws . String ( "S" ) ,
97
+ AttributeType : types . ScalarAttributeTypeS ,
95
98
},
96
99
},
97
- KeySchema : []* dynamodb .KeySchemaElement {
100
+ KeySchema : []types .KeySchemaElement {
98
101
{
99
102
AttributeName : aws .String ("PK" ),
100
- KeyType : aws . String ( "HASH" ) ,
103
+ KeyType : types . KeyTypeHash ,
101
104
},
102
105
{
103
106
AttributeName : aws .String ("SK" ),
104
- KeyType : aws . String ( "RANGE" ) ,
107
+ KeyType : types . KeyTypeRange ,
105
108
},
106
109
},
107
- BillingMode : aws . String ( "PAY_PER_REQUEST" ) ,
110
+ BillingMode : types . BillingModePayPerRequest ,
108
111
TableName : aws .String (TABLE_NAME ),
109
112
}
110
- _ , err = dynamoDbLock .DynamoDb .CreateTable (createtbl_input )
113
+ _ , err = dynamoDbLock .DynamoDb .CreateTable (ctx , createtbl_input )
111
114
if err != nil {
112
115
if os .Getenv ("DEBUG" ) != "" {
113
116
log .Printf ("%v\n " , err )
114
117
}
115
118
return err
116
119
}
117
120
118
- err = dynamoDbLock .waitUntilTableCreated ()
121
+ err = dynamoDbLock .waitUntilTableCreated (ctx )
119
122
if err != nil {
120
123
log .Printf ("%v\n " , err )
121
124
return err
@@ -125,7 +128,8 @@ func (dynamoDbLock *DynamoDbLock) createTableIfNotExists() error {
125
128
}
126
129
127
130
func (dynamoDbLock * DynamoDbLock ) Lock (transactionId int , resource string ) (bool , error ) {
128
- dynamoDbLock .createTableIfNotExists ()
131
+ ctx := context .Background ()
132
+ dynamoDbLock .createTableIfNotExists (ctx )
129
133
// TODO: remove timeout completely
130
134
now := time .Now ().Format (time .RFC3339 )
131
135
newTimeout := time .Now ().Add (TableLockTimeout ).Format (time .RFC3339 )
@@ -143,24 +147,28 @@ func (dynamoDbLock *DynamoDbLock) Lock(transactionId int, resource string) (bool
143
147
).Set (expression .Name ("timeout" ), expression .Value (newTimeout )),
144
148
).
145
149
Build ()
146
-
147
150
if err != nil {
148
151
return false , err
149
152
}
150
153
151
154
input := & dynamodb.UpdateItemInput {
152
- TableName : aws .String (TABLE_NAME ),
153
- Key : map [string ]* dynamodb.AttributeValue {"PK" : {S : aws .String ("LOCK" )}, "SK" : {S : aws .String ("RES#" + resource )}},
155
+ TableName : aws .String (TABLE_NAME ),
156
+ Key : map [string ]types.AttributeValue {
157
+ "PK" : & types.AttributeValueMemberS {Value : "LOCK" },
158
+ "SK" : & types.AttributeValueMemberS {Value : "RES#" + resource },
159
+ },
154
160
ConditionExpression : expr .Condition (),
155
161
ExpressionAttributeNames : expr .Names (),
156
162
ExpressionAttributeValues : expr .Values (),
157
163
UpdateExpression : expr .Update (),
158
164
}
159
165
160
- _ , err = dynamoDbLock .DynamoDb .UpdateItem (input )
166
+ _ , err = dynamoDbLock .DynamoDb .UpdateItem (ctx , input )
161
167
if err != nil {
162
- if aerr , ok := err .(awserr.Error ); ok {
163
- if aerr .Code () == dynamodb .ErrCodeConditionalCheckFailedException {
168
+ var apiError smithy.APIError
169
+ if errors .As (err , & apiError ) {
170
+ switch apiError .(type ) {
171
+ case * types.ConditionalCheckFailedException :
164
172
return false , nil
165
173
}
166
174
}
@@ -171,36 +179,50 @@ func (dynamoDbLock *DynamoDbLock) Lock(transactionId int, resource string) (bool
171
179
}
172
180
173
181
func (dynamoDbLock * DynamoDbLock ) Unlock (resource string ) (bool , error ) {
174
- dynamoDbLock .createTableIfNotExists ()
182
+ ctx := context .Background ()
183
+ dynamoDbLock .createTableIfNotExists (ctx )
175
184
input := & dynamodb.DeleteItemInput {
176
185
TableName : aws .String (TABLE_NAME ),
177
- Key : map [string ]* dynamodb.AttributeValue {"PK" : {S : aws .String ("LOCK" )}, "SK" : {S : aws .String ("RES#" + resource )}},
186
+ Key : map [string ]types.AttributeValue {
187
+ "PK" : & types.AttributeValueMemberS {Value : "LOCK" },
188
+ "SK" : & types.AttributeValueMemberS {Value : "RES#" + resource },
189
+ },
178
190
}
179
191
180
- _ , err := dynamoDbLock .DynamoDb .DeleteItem (input )
192
+ _ , err := dynamoDbLock .DynamoDb .DeleteItem (ctx , input )
181
193
if err != nil {
182
194
return false , err
183
195
}
184
196
return true , nil
185
197
}
186
198
187
199
func (dynamoDbLock * DynamoDbLock ) GetLock (lockId string ) (* int , error ) {
188
- dynamoDbLock .createTableIfNotExists ()
200
+ ctx := context .Background ()
201
+ dynamoDbLock .createTableIfNotExists (ctx )
189
202
input := & dynamodb.GetItemInput {
190
203
TableName : aws .String (TABLE_NAME ),
191
- Key : map [string ]* dynamodb.AttributeValue {"PK" : {S : aws .String ("LOCK" )}, "SK" : {S : aws .String ("RES#" + lockId )}},
204
+ Key : map [string ]types.AttributeValue {
205
+ "PK" : & types.AttributeValueMemberS {Value : "LOCK" },
206
+ "SK" : & types.AttributeValueMemberS {Value : "RES#" + lockId },
207
+ },
192
208
}
193
209
194
- result , err := dynamoDbLock .DynamoDb .GetItem (input )
210
+ result , err := dynamoDbLock .DynamoDb .GetItem (ctx , input )
195
211
if err != nil {
196
212
return nil , err
197
213
}
198
214
199
- if result .Item != nil {
200
- transactionId := result .Item ["transaction_id" ].N
201
- res , err := strconv .Atoi (* transactionId )
202
- return & res , err
215
+ type TransactionLock struct {
216
+ TransactionID int `dynamodbav:"transaction_id"`
203
217
}
204
218
219
+ var t TransactionLock
220
+ err = attributevalue .UnmarshalMap (result .Item , & t )
221
+ if err != nil {
222
+ return nil , err
223
+ }
224
+ if t .TransactionID != 0 {
225
+ return & t .TransactionID , nil
226
+ }
205
227
return nil , nil
206
228
}
0 commit comments