Skip to content

Commit 302a68e

Browse files
authored
docs(idempotency): add missing Lambda Context; note on thread-safe (#1732)
1 parent d7fc2b8 commit 302a68e

File tree

1 file changed

+75
-11
lines changed

1 file changed

+75
-11
lines changed

Diff for: docs/utilities/idempotency.md

+75-11
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,12 @@ When using `idempotent_function`, you must tell us which keyword parameter in yo
125125

126126
!!! info "We support JSON serializable data, [Python Dataclasses](https://docs.python.org/3.7/library/dataclasses.html){target="_blank"}, [Parser/Pydantic Models](parser.md){target="_blank"}, and our [Event Source Data Classes](./data_classes.md){target="_blank"}."
127127

128-
???+ warning
129-
Make sure to call your decorated function using keyword arguments
128+
???+ warning "Limitations"
129+
Make sure to call your decorated function using keyword arguments.
130+
131+
Decorated functions with `idempotent_function` are not thread-safe, if the caller uses threading, not the function computation itself.
132+
133+
DynamoDB Persistency layer uses a Resource client [which is not thread-safe](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/resources.html?highlight=multithreading#multithreading-or-multiprocessing-with-resources){target="_blank"}.
130134

131135
=== "batch_sample.py"
132136

@@ -1018,12 +1022,34 @@ with a truthy value. If you prefer setting this for specific tests, and are usin
10181022

10191023
=== "tests.py"
10201024

1021-
```python hl_lines="2 3"
1022-
def test_idempotent_lambda_handler(monkeypatch):
1025+
```python hl_lines="24-25"
1026+
from dataclasses import dataclass
1027+
1028+
import pytest
1029+
1030+
import app
1031+
1032+
1033+
@pytest.fixture
1034+
def lambda_context():
1035+
@dataclass
1036+
class LambdaContext:
1037+
function_name: str = "test"
1038+
memory_limit_in_mb: int = 128
1039+
invoked_function_arn: str = "arn:aws:lambda:eu-west-1:809313241:function:test"
1040+
aws_request_id: str = "52fdfc07-2182-154f-163f-5f0f9a621d72"
1041+
1042+
def get_remaining_time_in_millis(self) -> int:
1043+
return 5
1044+
1045+
return LambdaContext()
1046+
1047+
1048+
def test_idempotent_lambda_handler(monkeypatch, lambda_context):
10231049
# Set POWERTOOLS_IDEMPOTENCY_DISABLED before calling decorated functions
10241050
monkeypatch.setenv("POWERTOOLS_IDEMPOTENCY_DISABLED", 1)
10251051

1026-
result = handler()
1052+
result = handler({}, lambda_context)
10271053
...
10281054
```
10291055
=== "app.py"
@@ -1051,18 +1077,36 @@ To test with [DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/
10511077

10521078
=== "tests.py"
10531079

1054-
```python hl_lines="6 7 8"
1080+
```python hl_lines="24-27"
1081+
from dataclasses import dataclass
1082+
10551083
import boto3
1084+
import pytest
10561085

10571086
import app
10581087

1059-
def test_idempotent_lambda():
1088+
1089+
@pytest.fixture
1090+
def lambda_context():
1091+
@dataclass
1092+
class LambdaContext:
1093+
function_name: str = "test"
1094+
memory_limit_in_mb: int = 128
1095+
invoked_function_arn: str = "arn:aws:lambda:eu-west-1:809313241:function:test"
1096+
aws_request_id: str = "52fdfc07-2182-154f-163f-5f0f9a621d72"
1097+
1098+
def get_remaining_time_in_millis(self) -> int:
1099+
return 5
1100+
1101+
return LambdaContext()
1102+
1103+
def test_idempotent_lambda(lambda_context):
10601104
# Create our own Table resource using the endpoint for our DynamoDB Local instance
10611105
resource = boto3.resource("dynamodb", endpoint_url='http://localhost:8000')
10621106
table = resource.Table(app.persistence_layer.table_name)
10631107
app.persistence_layer.table = table
10641108

1065-
result = app.handler({'testkey': 'testvalue'}, {})
1109+
result = app.handler({'testkey': 'testvalue'}, lambda_context)
10661110
assert result['payment_id'] == 12345
10671111
```
10681112

@@ -1092,15 +1136,35 @@ This means it is possible to pass a mocked Table resource, or stub various metho
10921136

10931137
=== "tests.py"
10941138

1095-
```python hl_lines="6 7 8 9"
1139+
```python hl_lines="26-29"
1140+
from dataclasses import dataclass
10961141
from unittest.mock import MagicMock
10971142

1143+
import boto3
1144+
import pytest
1145+
10981146
import app
10991147

1100-
def test_idempotent_lambda():
1148+
1149+
@pytest.fixture
1150+
def lambda_context():
1151+
@dataclass
1152+
class LambdaContext:
1153+
function_name: str = "test"
1154+
memory_limit_in_mb: int = 128
1155+
invoked_function_arn: str = "arn:aws:lambda:eu-west-1:809313241:function:test"
1156+
aws_request_id: str = "52fdfc07-2182-154f-163f-5f0f9a621d72"
1157+
1158+
def get_remaining_time_in_millis(self) -> int:
1159+
return 5
1160+
1161+
return LambdaContext()
1162+
1163+
1164+
def test_idempotent_lambda(lambda_context):
11011165
table = MagicMock()
11021166
app.persistence_layer.table = table
1103-
result = app.handler({'testkey': 'testvalue'}, {})
1167+
result = app.handler({'testkey': 'testvalue'}, lambda_context)
11041168
table.put_item.assert_called()
11051169
...
11061170
```

0 commit comments

Comments
 (0)