@@ -34,6 +34,7 @@ storage layer, so you'll need to create a table first.
3434> Example using AWS Serverless Application Model (SAM)
3535
3636=== "template.yml"
37+
3738 ```yaml
3839 Resources:
3940 HelloWorldFunction:
@@ -76,32 +77,32 @@ You can quickly start by initializing the `DynamoDBPersistenceLayer` class outsi
7677with the ` idempotent ` decorator on your lambda handler. The only required parameter is ` table_name ` , but you likely
7778want to specify ` event_key_jmespath ` as well.
7879
79- ` event_key_jmespath ` : A JMESpath expression which will be used to extract the payload from the event your Lambda hander
80+ ` event_key_jmespath ` : A JMESpath expression which will be used to extract the payload from the event your Lambda handler
8081is called with. This payload will be used as the key to decide if future invocations are duplicates. If you don't pass
8182this parameter, the entire event will be used as the key.
8283
8384=== "app.py"
8485
8586 ```python hl_lines="2 6-9 11"
86- import json
87- from aws_lambda_powertools.utilities.idempotency import DynamoDBPersistenceLayer, idempotent
88-
89- # Treat everything under the "body" key in
90- # the event json object as our payload
91- persistence_layer = DynamoDBPersistenceLayer(
92- event_key_jmespath="body ",
93- table_name="IdempotencyTable"
94- )
87+ import json
88+ from aws_lambda_powertools.utilities.idempotency import DynamoDBPersistenceLayer, idempotent
89+
90+ # Treat everything under the "body" key in
91+ # the event json object as our payload
92+ persistence_layer = DynamoDBPersistenceLayer(
93+ table_name="IdempotencyTable ",
94+ event_key_jmespath="body",
95+ )
9596
96- @idempotent(persistence_store=persistence_layer)
97- def handler(event, context):
98- body = json.loads(event['body'])
99- payment = create_subscription_payment(
100- user=body['user'],
101- product=body['product_id']
102- )
103- ...
104- return {"message": "success", "statusCode": 200, "payment_id": payment.id}
97+ @idempotent(persistence_store=persistence_layer)
98+ def handler(event, context):
99+ body = json.loads(event['body'])
100+ payment = create_subscription_payment(
101+ user=body['user'],
102+ product=body['product_id']
103+ )
104+ ...
105+ return {"message": "success", "statusCode": 200, "payment_id": payment.id}
105106 ```
106107=== "Example event"
107108
@@ -171,17 +172,19 @@ In most cases, it is not desirable to store the idempotency records forever. Rat
171172same payload won't be executed within a period of time. By default, the period is set to 1 hour (3600 seconds). You can
172173change this window with the ` expires_after_seconds ` parameter:
173174
174- ``` python hl_lines="4"
175- DynamoDBPersistenceLayer(
176- event_key_jmespath = " body" ,
177- table_name = " IdempotencyTable" ,
178- expires_after_seconds = 5 * 60 # 5 minutes
175+ === "app.py"
176+
177+ ```python hl_lines="4"
178+ DynamoDBPersistenceLayer(
179+ table_name="IdempotencyTable",
180+ event_key_jmespath="body",
181+ expires_after_seconds=5*60, # 5 minutes
179182 )
183+ ```
180184
181- ```
182185This will mark any records older than 5 minutes as expired, and the lambda handler will be executed as normal if it is
183186invoked with a matching payload. If you have set the TTL field in DynamoDB like in the SAM example above, the record
184- will be automatically deleted from the table after a period of itme .
187+ will be automatically deleted from the table after a period of time .
185188
186189
187190### Handling concurrent executions
@@ -195,17 +198,19 @@ concurrent execution. If you receive this error, you can safely retry the operat
195198To reduce the number of lookups to the persistence storage layer, you can enable in memory caching with the
196199` use_local_cache ` parameter, which is disabled by default. This cache is local to each Lambda execution environment.
197200This means it will be effective in cases where your function's concurrency is low in comparison to the number of
198- "retry" invocations with the same payload. When enabled, the default is to cache a maxmum of 256 records in each Lambda
201+ "retry" invocations with the same payload. When enabled, the default is to cache a maximum of 256 records in each Lambda
199202execution environment. You can change this with the ` local_cache_max_items ` parameter.
200203
201- ``` python hl_lines="4 5"
202- DynamoDBPersistenceLayer(
203- event_key_jmespath = " body" ,
204- table_name = " IdempotencyTable" ,
205- use_local_cache = True ,
206- local_cache_max_items = 1000
204+ === "app.py"
205+
206+ ```python hl_lines="4 5"
207+ DynamoDBPersistenceLayer(
208+ table_name="IdempotencyTable",
209+ event_key_jmespath="body",
210+ use_local_cache=True,
211+ local_cache_max_items=1000
207212 )
208- ```
213+ ```
209214
210215
211216## Advanced
@@ -218,35 +223,37 @@ with the `payload_validation_jmespath` to specify which part of the event body s
218223idempotent invocations.
219224
220225=== "app.py"
226+
221227 ```python hl_lines="6"
222228 from aws_lambda_powertools.utilities.idempotency import DynamoDBPersistenceLayer, idempotent
223229
224- persistence_layer = DynamoDBPersistenceLayer(
225- event_key_jmespath="[userDetail, productId] ",
226- table_name="IdempotencyTable",)
227- payload_validation_jmespath="amount"
228- )
230+ persistence_layer = DynamoDBPersistenceLayer(
231+ table_name="IdempotencyTable ",
232+ event_key_jmespath="[userDetail, productId]",
233+ payload_validation_jmespath="amount"
234+ )
229235
230- @idempotent(persistence_store=persistence_layer)
231- def handler(event, context):
232- # Creating a subscription payment is a side
233- # effect of calling this function!
234- payment = create_subscription_payment(
235- user=event['userDetail']['username'],
236- product=event['product_id'],
237- amount=event['amount']
238- )
239- ...
240- return {"message": "success", "statusCode": 200,
241- "payment_id": payment.id, "amount": payment.amount}
236+ @idempotent(persistence_store=persistence_layer)
237+ def handler(event, context):
238+ # Creating a subscription payment is a side
239+ # effect of calling this function!
240+ payment = create_subscription_payment(
241+ user=event['userDetail']['username'],
242+ product=event['product_id'],
243+ amount=event['amount']
244+ )
245+ ...
246+ return {"message": "success", "statusCode": 200,
247+ "payment_id": payment.id, "amount": payment.amount}
242248 ```
243- === "Event"
249+ === "Example Event"
250+
244251 ```json
245252 {
246253 "userDetail": {
247254 "username": "User1",
248255 "user_email": "user@example.com"
249- },
256+ },
250257 "productId": 1500,
251258 "charge_type": "subscription",
252259 "amount": 500
@@ -264,13 +271,15 @@ amount field, we prevent this potentially confusing behaviour and instead raise
264271If you want to enforce that an idempotency key is required, you can set ` raise_on_no_idempotency_key ` to ` True ` ,
265272and we will raise ` IdempotencyKeyError ` if none was found.
266273
267- ``` python hl_lines="4"
268- DynamoDBPersistenceLayer(
269- event_key_jmespath = " body" ,
270- table_name = " IdempotencyTable" ,
271- raise_on_no_idempotency_key = True
274+ === "app.py"
275+
276+ ```python hl_lines="4"
277+ DynamoDBPersistenceLayer(
278+ table_name="IdempotencyTable",
279+ event_key_jmespath="body",
280+ raise_on_no_idempotency_key=True,
272281 )
273- ```
282+ ```
274283
275284### Changing dynamoDB attribute names
276285If you want to use an existing DynamoDB table, or wish to change the name of the attributes used to store items in the
@@ -288,53 +297,56 @@ validation_key_attr | "validation" | Hashed representation of the parts of the
288297This example demonstrates changing the attribute names to custom values:
289298
290299=== "app.py"
291- ```python hl_lines="5-10"
300+
301+ ```python hl_lines="4-8"
292302 persistence_layer = DynamoDBPersistenceLayer(
293- event_key_jmespath="[ userDetail, productId] ",
294303 table_name="IdempotencyTable",
304+ event_key_jmespath="[userDetail, productId]",
295305 key_attr="idempotency_key",
296306 expiry_attr="expires_at",
297307 status_attr="current_status",
298308 data_attr="result_data",
299309 validation_key_attr="validation_key"
300- )
310+ )
301311 ```
302312
303313### Customizing boto configuration
304314You can provide custom boto configuration or event bring your own boto3 session if required by using the ` boto_config `
305315or ` boto3_session ` parameters when constructing the persistence store.
306316
307317=== "Custom session"
318+
308319 ```python hl_lines="1 4 8"
309- import boto3
310- from aws_lambda_powertools.utilities.idempotency import DynamoDBPersistenceLayer, idempotent
311-
312- boto3_session = boto3.session.Session()
313- persistence_layer = DynamoDBPersistenceLayer(
314- event_key_jmespath="body ",
315- table_name="IdempotencyTable ",
316- boto3_session=boto3_session
317- )
320+ import boto3
321+ from aws_lambda_powertools.utilities.idempotency import DynamoDBPersistenceLayer, idempotent
322+
323+ boto3_session = boto3.session.Session()
324+ persistence_layer = DynamoDBPersistenceLayer(
325+ table_name="IdempotencyTable ",
326+ event_key_jmespath="body ",
327+ boto3_session=boto3_session
328+ )
318329
319- @idempotent(persistence_store=persistence_layer)
320- def handler(event, context):
321- ...
330+ @idempotent(persistence_store=persistence_layer)
331+ def handler(event, context):
332+ ...
322333 ```
323334=== "Custom config"
335+
324336 ```python hl_lines="1 4 8"
325- from botocore.config import Config
326- from aws_lambda_powertools.utilities.idempotency import DynamoDBPersistenceLayer, idempotent
327-
328- boto_config = Config()
329- persistence_layer = DynamoDBPersistenceLayer(
330- event_key_jmespath="body ",
331- table_name="IdempotencyTable ",
332- boto_config=boto_config
333- )
334-
335- @idempotent(persistence_store=persistence_layer)
336- def handler(event, context):
337- ...
337+ from botocore.config import Config
338+ from aws_lambda_powertools.utilities.idempotency import DynamoDBPersistenceLayer, idempotent
339+
340+ boto_config = Config()
341+ persistence_layer = DynamoDBPersistenceLayer(
342+ table_name="IdempotencyTable ",
343+ event_key_jmespath="body ",
344+ boto_config=boto_config
345+ )
346+
347+ @idempotent(persistence_store=persistence_layer)
348+ def handler(event, context):
349+ ...
338350 ```
339351
340352### Bring your own persistent store
@@ -357,14 +369,15 @@ The idempotency utility can be used with the `validator` decorator. Ensure that
357369 ` event_key_jmespath ` .
358370
359371=== "app.py"
372+
360373 ```python hl_lines="9 10"
361374 from aws_lambda_powertools.utilities.validation import validator, envelopes
362375 from aws_lambda_powertools.utilities.idempotency.idempotency import idempotent
363376
364377 persistence_layer = DynamoDBPersistenceLayer(
365- event_key_jmespath="[message, username]",
366378 table_name="IdempotencyTable",
367- )
379+ event_key_jmespath="[message, username]",
380+ )
368381
369382 @validator(envelope=envelopes.API_GATEWAY_HTTP)
370383 @idempotent(persistence_store=persistence_layer)
0 commit comments