Skip to content

Commit 6029a2c

Browse files
committed
docs: cleanup handling exceptions
Signed-off-by: heitorlessa <[email protected]>
1 parent 2b31c67 commit 6029a2c

File tree

3 files changed

+47
-50
lines changed

3 files changed

+47
-50
lines changed

docs/utilities/idempotency.md

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -316,41 +316,16 @@ To prevent extended failures, use **`register_lambda_context`** function from yo
316316

317317
### Handling exceptions
318318

319-
If you are using the `idempotent` decorator on your Lambda handler, any unhandled exceptions that are raised during the code execution will cause **the record in the persistence layer to be deleted**.
320-
This means that new invocations will execute your code again despite having the same payload. If you don't want the record to be deleted, you need to catch exceptions within the idempotent function and return a successful response.
319+
There are two failure modes that can cause new invocations to execute your code again despite having the same payload:
321320

322-
<center>
323-
```mermaid
324-
sequenceDiagram
325-
participant Client
326-
participant Lambda
327-
participant Persistence Layer
328-
Client->>Lambda: Invoke (event)
329-
Lambda->>Persistence Layer: Get or set (id=event.search(payload))
330-
activate Persistence Layer
331-
Note right of Persistence Layer: Locked during this time. Prevents multiple<br/>Lambda invocations with the same<br/>payload running concurrently.
332-
Lambda--xLambda: Call handler (event).<br/>Raises exception
333-
Lambda->>Persistence Layer: Delete record (id=event.search(payload))
334-
deactivate Persistence Layer
335-
Lambda-->>Client: Return error response
336-
```
337-
<i>Idempotent sequence exception</i>
338-
</center>
321+
* **Unhandled exception**. We catch them to delete the idempotency record to prevent inconsistencies, then propagate them.
322+
* **Persistent layer errors**. We raise **`IdempotencyPersistenceLayerError`** for any persistence layer errors _e.g., remove idempotency record_.
339323

340-
If you are using `idempotent_function`, any unhandled exceptions that are raised _inside_ the decorated function will cause the record in the persistence layer to be deleted, and allow the function to be executed again if retried.
324+
If an exception is handled or raised **outside** your decorated function, then idempotency will be maintained.
341325

342-
If an Exception is raised _outside_ the scope of the decorated function and after your function has been called, the persistent record will not be affected. In this case, idempotency will be maintained for your decorated function. Example:
343-
344-
=== "Handling exceptions"
345-
346-
```python hl_lines="18-22 28 31"
347-
--8<-- "examples/idempotency/src/working_with_exceptions.py"
348-
```
349-
350-
???+ warning
351-
**We will raise `IdempotencyPersistenceLayerError`** if any of the calls to the persistence layer fail unexpectedly.
352-
353-
As this happens outside the scope of your decorated function, you are not able to catch it if you're using the `idempotent` decorator on your Lambda handler.
326+
```python title="working_with_exceptions.py" hl_lines="21 32 38"
327+
--8<-- "examples/idempotency/src/working_with_exceptions.py"
328+
```
354329

355330
### Persistence layers
356331

@@ -646,6 +621,26 @@ sequenceDiagram
646621
<i>Concurrent identical in-flight requests</i>
647622
</center>
648623

624+
#### Unhandled exception
625+
626+
<center>
627+
```mermaid
628+
sequenceDiagram
629+
participant Client
630+
participant Lambda
631+
participant Persistence Layer
632+
Client->>Lambda: Invoke (event)
633+
Lambda->>Persistence Layer: Get or set (id=event.search(payload))
634+
activate Persistence Layer
635+
Note right of Persistence Layer: Locked during this time. Prevents multiple<br/>Lambda invocations with the same<br/>payload running concurrently.
636+
Lambda--xLambda: Call handler (event).<br/>Raises exception
637+
Lambda->>Persistence Layer: Delete record (id=event.search(payload))
638+
deactivate Persistence Layer
639+
Lambda-->>Client: Return error response
640+
```
641+
<i>Idempotent sequence exception</i>
642+
</center>
643+
649644
#### Lambda request timeout
650645

651646
<center>
Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,38 @@
1+
import os
2+
13
import requests
24

35
from aws_lambda_powertools.utilities.idempotency import (
46
DynamoDBPersistenceLayer,
57
IdempotencyConfig,
68
idempotent_function,
79
)
10+
from aws_lambda_powertools.utilities.idempotency.exceptions import IdempotencyPersistenceLayerError
811
from aws_lambda_powertools.utilities.typing import LambdaContext
912

10-
persistence_layer = DynamoDBPersistenceLayer(table_name="IdempotencyTable")
13+
table = os.getenv("IDEMPOTENCY_TABLE")
14+
persistence_layer = DynamoDBPersistenceLayer(table_name=table)
1115

1216
config = IdempotencyConfig()
1317

1418

15-
def lambda_handler(event: dict, context: LambdaContext):
16-
# If an exception is raised here, no idempotent record will ever get created as the
17-
# idempotent function does not get called
18-
try:
19-
endpoint = "https://jsonplaceholder.typicode.com/comments/" # change this endpoint to force an exception
20-
requests.get(endpoint)
21-
except Exception as exc:
22-
return str(exc)
23-
24-
call_external_service(data={"user": "user1", "id": 5})
25-
26-
# This exception will not cause the idempotent record to be deleted, since it
27-
# happens after the decorated function has been successfully called
28-
raise Exception
29-
30-
3119
@idempotent_function(data_keyword_argument="data", config=config, persistence_store=persistence_layer)
3220
def call_external_service(data: dict):
21+
# Any exception raised will lead to idempotency record to be deleted
3322
result: requests.Response = requests.post(
3423
"https://jsonplaceholder.typicode.com/comments/",
35-
json={"user": data["user"], "transaction_id": data["id"]},
24+
json=data,
3625
)
3726
return result.json()
27+
28+
29+
def lambda_handler(event: dict, context: LambdaContext):
30+
try:
31+
call_external_service(data=event)
32+
except IdempotencyPersistenceLayerError as e:
33+
# No idempotency, but you can decide to error differently.
34+
raise RuntimeError(f"Oops, can't talk to persistence layer. Permissions? error: {e}")
35+
36+
# This exception will not impact the idempotency of 'call_external_service'
37+
# because it happens in isolation, or outside their scope.
38+
raise SyntaxError("Oops, this shouldn't be here.")

includes/abbreviations.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
*[observability provider]: An AWS Lambda Observability Partner
2+
*[unhandled exception]: An exception that is not caught by any explicit try/except block

0 commit comments

Comments
 (0)