Skip to content

Commit 2344e01

Browse files
committed
docs: cleanup handling exceptions
Signed-off-by: heitorlessa <[email protected]>
1 parent eb42534 commit 2344e01

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
@@ -305,41 +305,16 @@ Here is an example on how you register the Lambda context in your handler:
305305

306306
### Handling exceptions
307307

308-
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**.
309-
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.
308+
There are two failure modes that can cause new invocations to execute your code again despite having the same payload:
310309

311-
<center>
312-
```mermaid
313-
sequenceDiagram
314-
participant Client
315-
participant Lambda
316-
participant Persistence Layer
317-
Client->>Lambda: Invoke (event)
318-
Lambda->>Persistence Layer: Get or set (id=event.search(payload))
319-
activate Persistence Layer
320-
Note right of Persistence Layer: Locked during this time. Prevents multiple<br/>Lambda invocations with the same<br/>payload running concurrently.
321-
Lambda--xLambda: Call handler (event).<br/>Raises exception
322-
Lambda->>Persistence Layer: Delete record (id=event.search(payload))
323-
deactivate Persistence Layer
324-
Lambda-->>Client: Return error response
325-
```
326-
<i>Idempotent sequence exception</i>
327-
</center>
310+
* **Unhandled exception**. We catch them to delete the idempotency record to prevent inconsistencies, then propagate them.
311+
* **Persistent layer errors**. We raise **`IdempotencyPersistenceLayerError`** for any persistence layer errors _e.g., remove idempotency record_.
328312

329-
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.
313+
If an exception is handled or raised **outside** your decorated function, then idempotency will be maintained.
330314

331-
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:
332-
333-
=== "Handling exceptions"
334-
335-
```python hl_lines="18-22 28 31"
336-
--8<-- "examples/idempotency/src/working_with_exceptions.py"
337-
```
338-
339-
???+ warning
340-
**We will raise `IdempotencyPersistenceLayerError`** if any of the calls to the persistence layer fail unexpectedly.
341-
342-
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.
315+
```python title="working_with_exceptions.py" hl_lines="21 32 38"
316+
--8<-- "examples/idempotency/src/working_with_exceptions.py"
317+
```
343318

344319
### Persistence layers
345320

@@ -635,6 +610,26 @@ sequenceDiagram
635610
<i>Concurrent identical in-flight requests</i>
636611
</center>
637612

613+
#### Unhandled exception
614+
615+
<center>
616+
```mermaid
617+
sequenceDiagram
618+
participant Client
619+
participant Lambda
620+
participant Persistence Layer
621+
Client->>Lambda: Invoke (event)
622+
Lambda->>Persistence Layer: Get or set (id=event.search(payload))
623+
activate Persistence Layer
624+
Note right of Persistence Layer: Locked during this time. Prevents multiple<br/>Lambda invocations with the same<br/>payload running concurrently.
625+
Lambda--xLambda: Call handler (event).<br/>Raises exception
626+
Lambda->>Persistence Layer: Delete record (id=event.search(payload))
627+
deactivate Persistence Layer
628+
Lambda-->>Client: Return error response
629+
```
630+
<i>Idempotent sequence exception</i>
631+
</center>
632+
638633
#### Lambda request timeout
639634

640635
<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)