Skip to content

Commit f0596a4

Browse files
Improving doc
1 parent be0f3f7 commit f0596a4

File tree

3 files changed

+52
-12
lines changed

3 files changed

+52
-12
lines changed

aws_lambda_powertools/utilities/idempotency/base.py

+1
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ def _handle_for_status(self, data_record: DataRecord) -> Optional[Any]:
231231
if response_dict is not None:
232232
serialized_response = self.output_serializer.from_dict(response_dict)
233233
if self.config.response_hook is not None:
234+
logger.debug("Response hook configured, invoking function")
234235
return self.config.response_hook(
235236
serialized_response,
236237
data_record,

docs/utilities/idempotency.md

+45-7
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,40 @@ sequenceDiagram
454454
<i>Idempotent successful request cached</i>
455455
</center>
456456

457+
#### Successful request with response_hook configured
458+
459+
<center>
460+
```mermaid
461+
sequenceDiagram
462+
participant Client
463+
participant Lambda
464+
participant Response hook
465+
participant Persistence Layer
466+
alt initial request
467+
Client->>Lambda: Invoke (event)
468+
Lambda->>Persistence Layer: Get or set idempotency_key=hash(payload)
469+
activate Persistence Layer
470+
Note over Lambda,Persistence Layer: Set record status to INPROGRESS. <br> Prevents concurrent invocations <br> with the same payload
471+
Lambda-->>Lambda: Call your function
472+
Lambda->>Persistence Layer: Update record with result
473+
deactivate Persistence Layer
474+
Persistence Layer-->>Persistence Layer: Update record
475+
Note over Lambda,Persistence Layer: Set record status to COMPLETE. <br> New invocations with the same payload <br> now return the same result
476+
Lambda-->>Client: Response sent to client
477+
else retried request
478+
Client->>Lambda: Invoke (event)
479+
Lambda->>Persistence Layer: Get or set idempotency_key=hash(payload)
480+
activate Persistence Layer
481+
Persistence Layer-->>Response hook: Already exists in persistence layer.
482+
deactivate Persistence Layer
483+
Note over Response hook,Persistence Layer: Record status is COMPLETE and not expired
484+
Response hook->>Lambda: Response hook invoked
485+
Lambda-->>Client: Same response sent to client
486+
end
487+
```
488+
<i>Idempotent successful request with response hook</i>
489+
</center>
490+
457491
#### Expired idempotency records
458492

459493
<center>
@@ -708,7 +742,7 @@ Idempotent decorator can be further configured with **`IdempotencyConfig`** as s
708742
| **use_local_cache** | `False` | Whether to locally cache idempotency results |
709743
| **local_cache_max_items** | 256 | Max number of items to store in local cache |
710744
| **hash_function** | `md5` | Function to use for calculating hashes, as provided by [hashlib](https://docs.python.org/3/library/hashlib.html){target="_blank" rel="nofollow"} in the standard library. |
711-
| **response_hook** | `None` | Function to use for processing the stored Idempotent response. This function hook is called when an existing idempotent response is found. See [Manipulating The Idempotent Response](idempotency.md#manipulating-the-idempotent-response) |
745+
| **response_hook** | `None` | Function to use for processing the stored Idempotent response. This function hook is called when an existing idempotent response is found. See [Manipulating The Idempotent Response](idempotency.md#manipulating-the-idempotent-response) |
712746

713747
### Handling concurrent executions with the same payload
714748

@@ -912,15 +946,19 @@ You can create your own persistent store from scratch by inheriting the `BasePer
912946

913947
### Manipulating the Idempotent Response
914948

915-
The IdempotentConfig allows you to specify a _**response_hook**_ which is a function that will be called when an already returned response is loaded from the PersistenceStore. The Hook function will be called with the current de-serialized response object and the Idempotent DataRecord.
916-
917-
You can provide the _**response_hook**_ using _**IdempotentConfig**_.
949+
You can set up a `response_hook` in the `IdempotentConfig` class to access the returned data when an operation is idempotent. The hook function will be called with the current deserialized response object and the Idempotency record.
918950

919951
=== "Using an Idempotent Response Hook"
920952

921-
```python hl_lines="15-25 30"
922-
--8<-- "examples/idempotency/src/working_with_response_hook.py"
923-
```
953+
```python hl_lines="15 17 20 31"
954+
--8<-- "examples/idempotency/src/working_with_response_hook.py"
955+
```
956+
957+
=== "Sample event"
958+
959+
```json
960+
--8<-- "examples/idempotency/src/getting_started_with_idempotency_payload.json"
961+
```
924962

925963
???+ info "Info: Using custom de-serialization?"
926964

examples/idempotency/src/working_with_response_hook.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,21 @@
1414

1515
def my_response_hook(response: Dict, idempotent_data: DataRecord) -> Dict:
1616
# Return inserted Header data into the Idempotent Response
17-
response["headers"]["x-idempotent-key"] = idempotent_data.idempotency_key
17+
response["x-idempotent-key"] = idempotent_data.idempotency_key
1818

1919
# expiry_timestamp could be None so include if set
20-
if idempotent_data.expiry_timestamp:
21-
expiry_time = datetime.fromtimestamp(idempotent_data.expiry_timestamp)
22-
response["headers"]["x-idempotent-expiration"] = expiry_time.isoformat()
20+
expiry_timestamp = idempotent_data.expiry_timestamp
21+
if expiry_timestamp:
22+
expiry_time = datetime.fromtimestamp(int(expiry_timestamp))
23+
response["x-idempotent-expiration"] = expiry_time.isoformat()
2324

2425
# Must return the response here
2526
return response
2627

2728

2829
persistence_layer = DynamoDBPersistenceLayer(table_name="IdempotencyTable")
2930

30-
config = IdempotencyConfig(event_key_jmespath="body", response_hook=my_response_hook)
31+
config = IdempotencyConfig(response_hook=my_response_hook)
3132

3233

3334
@idempotent(persistence_store=persistence_layer, config=config)

0 commit comments

Comments
 (0)