You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/utilities/idempotency.md
+45-31
Original file line number
Diff line number
Diff line change
@@ -52,12 +52,22 @@ classDiagram
52
52
53
53
## Getting started
54
54
55
-
### IAM Permissions
55
+
### Installation
56
+
Install the library in your project
57
+
```shell
58
+
npm i @aws-lambda-powertools/idempotency @aws-sdk/client-dynamodb
59
+
```
60
+
61
+
While we support Amazon DynamoDB as a persistance layer out of the box, you need to bring your own AWS SDK for JavaScript v3 DynamoDB client.
56
62
57
-
Your Lambda function IAM Role must have `dynamodb:GetItem`, `dynamodb:PutItem`, `dynamodb:UpdateItem` and `dynamodb:DeleteItem` IAM permissions before using this feature.
58
63
59
64
???+ note
60
-
If you're using one of our examples: [AWS Serverless Application Model (SAM)](#required-resources) or [Terraform](#required-resources) the required permissions are already included.
65
+
This utility supports **[AWS SDK for JavaScript v3](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/){target="_blank"} only**. If you are using the `nodejs18.x` runtime, the AWS SDK for JavaScript v3 is already installed and you can install only the utility.
66
+
67
+
68
+
### IAM Permissions
69
+
70
+
Your Lambda function IAM Role must have `dynamodb:GetItem`, `dynamodb:PutItem`, `dynamodb:UpdateItem` and `dynamodb:DeleteItem` IAM permissions before using this feature. If you're using one of our examples: [AWS Serverless Application Model (SAM)](#required-resources) or [Terraform](#required-resources) the required permissions are already included.
61
71
62
72
### Required resources
63
73
@@ -69,10 +79,10 @@ As of now, Amazon DynamoDB is the only supported persistent storage layer, so yo
69
79
70
80
If you're not [changing the default configuration for the DynamoDB persistence layer](#dynamodbpersistencelayer), this is the expected default configuration:
| Partition key |`id`| The id of each idempotency record which a combination of `functionName#hashOfPayload`. |
85
+
| TTL attribute name |`expiration`| This can only be configured after your table is created if you're using AWS Console. |
76
86
77
87
???+ tip "Tip: You can share a single state table for all functions"
78
88
You can reuse the same DynamoDB table to store idempotency state. We add the Lambda function name in addition to the idempotency key as a hash key.
@@ -212,26 +222,26 @@ If you're not [changing the default configuration for the DynamoDB persistence l
212
222
213
223
You can quickly start by initializing the `DynamoDBPersistenceLayer` class and using it with the `makeIdempotent` function wrapper on your Lambda handler.
214
224
215
-
???+ note
216
-
In this example, the entire Lambda handler is treated as a single idempotent operation. If your Lambda handler can cause multiple side effects, or you're only interested in making a specific logic idempotent, use the `makeIdempotent` high-order function only on the function that needs to be idempotent.
217
-
218
-
!!! tip "See [Choosing a payload subset for idempotency](#choosing-a-payload-subset-for-idempotency) for more elaborate use cases."
After processing this request successfully, a second request containing the exact same payload above will now return the same response, ensuring our customer isn't charged twice.
233
238
234
-
!!! question "New to idempotency concept? Please review our [Terminology](#terminology) section if you haven't yet."
239
+
240
+
???+ note
241
+
In this example, the entire Lambda handler is treated as a single idempotent operation. If your Lambda handler can cause multiple side effects, or you're only interested in making a specific logic idempotent, use the `makeIdempotent` high-order function only on the function that needs to be idempotent.
242
+
243
+
See [Choosing a payload subset for idempotency](#choosing-a-payload-subset-for-idempotency) for more elaborate use cases.
244
+
235
245
236
246
You can also use the `makeIdempotent` function wrapper on any function that returns a response to make it idempotent. This is useful when you want to make a specific logic idempotent, for example when your Lambda handler performs multiple side effects and you only want to make a specific one idempotent.
237
247
@@ -240,21 +250,21 @@ You can also use the `makeIdempotent` function wrapper on any function that retu
240
250
241
251
When using `makeIdempotent` on arbitrary functions, you can tell us which argument in your function signature has the data we should use via **`dataIndexArgument`**. If you don't specify this argument, we'll use the first argument in the function signature.
242
252
243
-
???+ note
244
-
The function in the example below has two arguments, note that while wrapping it with the `makeIdempotent` high-order function, we specify the `dataIndexArgument` as `1` to tell the decorator that the second argument is the one that contains the data we should use to make the function idempotent. Remember that arguments are zero-indexed, so the first argument is `0`, the second is `1`, and so on.
The function this example has two arguments, note that while wrapping it with the `makeIdempotent` high-order function, we specify the `dataIndexArgument` as `1` to tell the decorator that the second argument is the one that contains the data we should use to make the function idempotent. Remember that arguments are zero-indexed, so the first argument is `0`, the second is `1`, and so on.
266
+
267
+
258
268
### MakeHandlerIdempotent Middy middleware
259
269
260
270
!!! tip "A note about Middy"
@@ -269,28 +279,25 @@ If you are using [Middy](https://middy.js.org){target="_blank"} as your middlewa
???+ tip "Tip: Dealing with always changing payloads"
281
-
When dealing with a more elaborate payload, where parts of the payload always change, you should use the **`eventKeyJmesPath`** parameter.
282
-
283
-
Use [`IdempotencyConfig`](#customizing-the-default-behavior) to instruct the idempotent decorator to only use a portion of your payload to verify whether a request is idempotent, and therefore it should not be retried.
290
+
Use [`IdempotencyConfig`](#customizing-the-default-behavior) to instruct the idempotent decorator to only use a portion of your payload to verify whether a request is idempotent, and therefore it should not be retried. When dealing with a more elaborate payload, where parts of the payload always change, you should use the **`eventKeyJmesPath`** parameter.
284
291
285
-
> **Payment scenario**
292
+
**Payment scenario**
286
293
287
294
In this example, we have a Lambda handler that creates a payment for a user subscribing to a product. We want to ensure that we don't accidentally charge our customer by subscribing them more than once.
288
295
289
296
Imagine the function executes successfully, but the client never receives the response due to a connection issue. It is safe to retry in this instance, as the idempotent decorator will return a previously saved response.
290
297
291
298
**What we want here** is to instruct Idempotency to use the `user` and `productId` fields from our incoming payload as our idempotency key. If we were to treat the entire request as our idempotency key, a simple HTTP header or timestamp change would cause our customer to be charged twice.
292
299
293
-
???+ tip "Deserializing JSON strings in payloads for increased accuracy."
300
+
???+ warning "Deserializing JSON strings in payloads for increased accuracy."
294
301
The payload extracted by the `eventKeyJmesPath` is treated as a string by default. This means there could be differences in whitespace even when the JSON payload itself is identical.
295
302
296
303
=== "index.ts"
@@ -334,26 +341,26 @@ Imagine the function executes successfully, but the client never receives the re
334
341
}
335
342
```
336
343
337
-
=== "Types"
344
+
=== "types.ts"
338
345
339
346
```typescript
340
347
--8<-- "docs/snippets/idempotency/types.ts::13"
341
348
```
342
349
343
350
### Lambda timeouts
344
351
345
-
???+ note
346
-
This is automatically done when you wrap your Lambda handler with the [makeIdempotent](#makeIdempotent-function-wrapper) function wrapper, or use the [`makeHandlerIdempotent`](#makeHandlerIdempotent-middy-middleware) Middy middleware.
347
352
348
-
To prevent against extended failed retries when a [Lambda function times out](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-verify-invocation-timeouts/), Powertools for AWS calculates and includes the remaining invocation available time as part of the idempotency record.
353
+
354
+
To prevent against extended failed retries when a [Lambda function times out](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-verify-invocation-timeouts/), Powertools for AWS Lambda calculates and includes the remaining invocation available time as part of the idempotency record.
355
+
This is automatically done when you wrap your Lambda handler with the [makeIdempotent](#makeIdempotent-function-wrapper) function wrapper, or use the [`makeHandlerIdempotent`](#makeHandlerIdempotent-middy-middleware) Middy middleware.
349
356
350
357
???+ example
351
358
If a second invocation happens **after** this timestamp, and the record is marked as `INPROGRESS`, we will execute the invocation again as if it was in the `EXPIRED` state (e.g, `expire_seconds` field elapsed).
352
359
353
360
This means that if an invocation expired during execution, it will be quickly executed again on the next retry.
354
361
355
362
???+ important
356
-
If you are only using the [makeIdempotent function wrapper](#makeIdempotent-function-wrapper) to guard isolated parts of your code, you must use `registerLambdaContext` available in the [idempotency config object](#customizing-the-default-behavior) to benefit from this protection.
363
+
If you are only using the [makeIdempotent function wrapper](#makeIdempotent-function-wrapper) to guard isolated parts of your code outside of your handler, you must use `registerLambdaContext` available in the [idempotency config object](#customizing-the-default-behavior) to benefit from this protection.
357
364
358
365
Here is an example on how you register the Lambda context in your handler:
359
366
@@ -371,6 +378,7 @@ This means that new invocations will execute your code again despite having the
371
378
<center>
372
379
```mermaid
373
380
sequenceDiagram
381
+
autonumber
374
382
participant Client
375
383
participant Lambda
376
384
participant Persistence Layer
@@ -410,6 +418,7 @@ The following sequence diagrams explain how the Idempotency feature behaves unde
410
418
<center>
411
419
```mermaid
412
420
sequenceDiagram
421
+
autonumber
413
422
participant Client
414
423
participant Lambda
415
424
participant Persistence Layer
@@ -444,6 +453,7 @@ sequenceDiagram
444
453
<center>
445
454
```mermaid
446
455
sequenceDiagram
456
+
autonumber
447
457
participant Client
448
458
participant Lambda
449
459
participant Persistence Layer
@@ -474,6 +484,7 @@ sequenceDiagram
474
484
<center>
475
485
```mermaid
476
486
sequenceDiagram
487
+
autonumber
477
488
participant Client
478
489
participant Lambda
479
490
participant Persistence Layer
@@ -509,6 +520,7 @@ sequenceDiagram
509
520
<center>
510
521
```mermaid
511
522
sequenceDiagram
523
+
autonumber
512
524
participant Client
513
525
participant Lambda
514
526
participant Persistence Layer
@@ -537,6 +549,7 @@ sequenceDiagram
537
549
<center>
538
550
```mermaid
539
551
sequenceDiagram
552
+
autonumber
540
553
participant Client
541
554
participant Lambda
542
555
participant Persistence Layer
@@ -570,6 +583,7 @@ sequenceDiagram
570
583
<center>
571
584
```mermaid
572
585
sequenceDiagram
586
+
autonumber
573
587
participant Client
574
588
participant Lambda
575
589
participant Persistence Layer
@@ -794,4 +808,4 @@ The example function above would cause data to be stored in DynamoDB like this:
794
808
## Extra resources
795
809
796
810
If you're interested in a deep dive on how Amazon uses idempotency when building our APIs, check out
0 commit comments