Closed
Description
Expected Behaviour
A function that (inadvertently) updates the event it has received should execute successfully, and have one idempotency document written.
Current Behaviour
A function that (inadvertently) updates the event it has received executes successfully, but has two documents corresponding to it's execution:
- An initial document with a hashed idempotency key based on the original payload that will be stuck in INPROGRESS and has no return data
- A second document with a hashed idempotency key based on the mutated payload with status COMPLETED and the correct return value
Code snippet
@pytest.mark.parametrize("idempotency_config", [{"use_local_cache": False}, {"use_local_cache": True}], indirect=True)
def test_idempotent_lambda_first_execution_event_mutation(
idempotency_config: IdempotencyConfig,
persistence_store: DynamoDBPersistenceLayer,
lambda_apigw_event,
expected_params_update_item,
expected_params_put_item,
lambda_response,
serialized_lambda_response,
deserialized_lambda_response,
hashed_idempotency_key,
lambda_context,
):
"""
Test idempotent decorator where lambda_handler mutates the event
"""
stubber = stub.Stubber(persistence_store.table.meta.client)
ddb_response = {}
stubber.add_response("put_item", ddb_response, expected_params_put_item)
stubber.add_response("update_item", ddb_response, expected_params_update_item)
stubber.activate()
@idempotent(config=idempotency_config, persistence_store=persistence_store)
def lambda_handler(event, context):
event.popitem() # <- 💣
return lambda_response
lambda_handler(lambda_apigw_event, lambda_context)
stubber.assert_no_pending_responses()
stubber.deactivate()
Possible Solution
A few options:
- Create the idempotency key on entry and save it (in say
self.idempotency_key
) - Use
copy.deepcopy()
when savingself.data
which forces a pass by value and gets the result of hash function stable
The former solution would be more performant, the latter less code.
Steps to Reproduce
Add the idempotency decorator to any lambda function, update the event data, ie: event.popitem()
and observe that 2 DDB documents were written of which one is stuck in INPROGRESS until it's TTLed
AWS Lambda Powertools for Python version
latest
AWS Lambda function runtime
{"label"=>"3.8"}
Packaging format used
{"label"=>"PyPi"}
Debugging logs
No response