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
@@ -12,6 +12,7 @@ The idempotency utility provides a simple solution to convert your Lambda functi
12
12
* Select a subset of the event as the idempotency key using JMESPath expressions
13
13
* Set a time window in which records with the same payload should be considered duplicates
14
14
* Expires in-progress executions if the Lambda function times out halfway through
15
+
* Support for Amazon DynamoDB, Valkey, Redis OSS, or any Redis-compatible cache as the persistence layer
15
16
16
17
## Terminology
17
18
@@ -49,40 +50,29 @@ classDiagram
49
50
50
51
## Getting started
51
52
52
-
### Installation
53
+
!!! tip
54
+
Throughout the documentation we use Amazon DynamoDB as the default persistence layer. If you prefer to use a cache based persistence layer, you can learn more in the [cache database](#cache-database) and [`CachePersistenceLayer`](#cachepersistencelayer) sections.
53
55
54
-
Install the library in your project
56
+
### Amazon DynamoDB
55
57
56
58
```shell
57
59
npm i @aws-lambda-powertools/idempotency @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
58
60
```
59
61
60
-
While we support Amazon DynamoDB as a persistence layer out of the box, you need to bring your own AWS SDK for JavaScript v3 DynamoDB client.
62
+
#### IAM Permissions
61
63
62
-
???+ note
63
-
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 or newer, the AWS SDK for JavaScript v3 is already installed and you can install only the utility.
64
-
65
-
### IAM Permissions
66
-
67
-
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.
68
-
69
-
### Required resources
64
+
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 below the required permissions are already included.
70
65
71
-
Before getting started, you need to create a persistent storage layer where the idempotency utility can store its state - your lambda functions will need read and write access to it.
66
+
#### Table configuration
72
67
73
-
As of now, Amazon DynamoDB is the only supported persistent storage layer, so you'll need to create a table first.
74
-
75
-
**Default table configuration**
76
-
77
-
If you're not [changing the default configuration for the DynamoDB persistence layer](#dynamodbpersistencelayer), this is the expected default configuration:
68
+
Unless you're looking to use an [existing table or customize each attribute](#dynamodbpersistencelayer), you only need the following:
| Partition key |`id`| The id of each idempotency record which a combination of `functionName#hashOfPayload`. |
82
73
| TTL attribute name |`expiration`| This can only be configured after your table is created if you're using AWS Console. |
83
74
84
-
???+ tip "Tip: You can share a single state table for all functions"
85
-
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.
75
+
You **can** use a single DynamoDB table for all functions using this utility. We use the function name in addition to the idempotency key as a hash key.
86
76
87
77
=== "AWS Cloud Development Kit (CDK) example"
88
78
@@ -102,17 +92,51 @@ If you're not [changing the default configuration for the DynamoDB persistence l
???+ warning "Warning: Large responses with DynamoDB persistence layer"
106
-
When using this utility with DynamoDB, your function's responses must be [smaller than 400KB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html#limits-items){target="_blank"}.
95
+
##### Limitations
96
+
97
+
***DynamoDB restricts [item sizes to 400KB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html#limits-items)**. This means that your idempotent function's response must be smaller than 400KB, otherwise your function will fail. Consider using the [cache persistence layer](#cache-database) if you need to store larger responses.
98
+
***Expect 2 WCUs per non-idempotent call**. During the first invocation, we use `PutItem` for locking and `UpdateItem` for completion. Consider reviewing [DynamoDB pricing documentation](https://aws.amazon.com/dynamodb/pricing/) to estimate cost.
99
+
***Expect 1 RCU per idempotent calls**. On subsequent invocations, we use `PutItem` to optimistically attempt to lock the record using `ConditionExpression` and `ReturnValuesOnConditionCheckFailure` to return the record if it exists. This is a single read operation.
100
+
101
+
### Cache database
102
+
103
+
Depending on the persistence layer you want to use, install the library and the corresponding peer dependencies.
104
+
105
+
=== "Valkey"
106
+
```shell
107
+
npm i @aws-lambda-powertools/idempotency@valkey/valkey-glide
108
+
```
109
+
110
+
=== "Redis OSS"
111
+
```shell
112
+
npm i @aws-lambda-powertools/idempotency@redis/client
113
+
```
114
+
115
+
We recommend starting with a managed cache service, such as [Amazon ElastiCache for Valkey and for Redis OSS](https://aws.amazon.com/elasticache/redis/){target="_blank"} or [Amazon MemoryDB](https://aws.amazon.com/memorydb/){target="_blank"}.
107
116
108
-
Larger items cannot be written to DynamoDB and will cause exceptions.
117
+
In both services, you'll need to configure [VPC access](https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html){target="_blank"} to your AWS Lambda and permissions for writing and reading from the cache.
109
118
110
-
???+ info "Info: DynamoDB"
111
-
Each function invocation will make only 1 request to DynamoDB by using DynamoDB's [conditional expressions](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ConditionExpressions.html){target="_blank"} to ensure that we don't overwrite existing records,
112
-
and [ReturnValuesOnConditionCheckFailure](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html#DDB-PutItem-request-ReturnValuesOnConditionCheckFailure){target="_blank"} to return the record if it exists.
113
-
See [AWS Blog post on handling conditional write errors](https://aws.amazon.com/blogs/database/handle-conditional-write-errors-in-high-concurrency-scenarios-with-amazon-dynamodb/) for more details.
114
-
For retried invocations, you will see 1WCU and 1RCU.
115
-
Review the [DynamoDB pricing documentation](https://aws.amazon.com/dynamodb/pricing/){target="_blank"} to estimate the cost.
1. You can use the same template for Redis OSS, just replace the engine to `redis`.
138
+
2. Replace the Security Group ID and Subnet ID to match your VPC settings.
139
+
3. Replace the Security Group ID and Subnet ID to match your VPC settings.
116
140
117
141
### MakeIdempotent function wrapper
118
142
@@ -523,7 +547,29 @@ sequenceDiagram
523
547
<i>Optional idempotency key</i>
524
548
</center>
525
549
526
-
## Advanced
550
+
#### Race condition with Cache
551
+
552
+
<center>
553
+
```mermaid
554
+
graph TD;
555
+
A(Existing orphan record in cache)-->A1;
556
+
A1[Two Lambda invoke at same time]-->B1[Lambda handler1];
557
+
B1-->B2[Fetch from Cache];
558
+
B2-->B3[Handler1 got orphan record];
559
+
B3-->B4[Handler1 acquired lock];
560
+
B4-->B5[Handler1 overwrite orphan record]
561
+
B5-->B6[Handler1 continue to execution];
562
+
A1-->C1[Lambda handler2];
563
+
C1-->C2[Fetch from Cache];
564
+
C2-->C3[Handler2 got orphan record];
565
+
C3-->C4[Handler2 failed to acquire lock];
566
+
C4-->C5[Handler2 wait and fetch from Cache];
567
+
C5-->C6[Handler2 return without executing];
568
+
B6-->D(Lambda handler executed only once);
569
+
C6-->D;
570
+
```
571
+
<i>Race condition with Cache</i>
572
+
</center>
527
573
528
574
### Persistence layers
529
575
@@ -551,6 +597,44 @@ When using DynamoDB as a persistence layer, you can alter the attribute names by
551
597
|**sortKeyAttr**||| Sort key of the table (if table is configured with a sort key). |
552
598
|**staticPkValue**||`idempotency#{LAMBDA_FUNCTION_NAME}`| Static value to use as the partition key. Only used when **sort_key_attr** is set. |
553
599
600
+
#### CachePersistenceLayer
601
+
602
+
The `CachePersistenceLayer` enables you to use Valkey, Redis OSS, or any Redis-compatible cache as the persistence layer for idempotency state. You need to provide your own cache client.
603
+
604
+
We recommend using [`@valkey/valkey-glide`](https://www.npmjs.com/package/@valkey/valkey-glide){target="_blank"} for Valkey or [`@redis/client`](https://www.npmjs.com/package/@redis/client){target="_blank"} for Redis. However, any Redis OSS-compatible client should work.
605
+
606
+
???+ info
607
+
Make sure your cache client is configured and connected before using it with `CachePersistenceLayer`.
Idempotent decorator can be further configured with **`IdempotencyConfig`** as seen in the previous examples. These are the available options for further configuration
@@ -861,6 +945,22 @@ When testing your Lambda function locally, you can use a local DynamoDB instance
Likewise, when using a cache database, you can use a local Valkey or Redis-OSS instance as a local server and replace the endpoint and port in the environment variables.
0 commit comments