Skip to content

Commit e2cad31

Browse files
mploskiRelease botMichal Ploski
authored
Fix(idempotency): Log nested exception message (#1813)
Co-authored-by: Release bot <aws-devax-open-source@amazon.com> Co-authored-by: Michal Ploski <mploski@amazon.com>
1 parent 20ca7ed commit e2cad31

File tree

3 files changed

+54
-14
lines changed

3 files changed

+54
-14
lines changed

aws_lambda_powertools/utilities/idempotency/base.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,9 @@ def _process_idempotency(self):
113113
record = self._get_idempotency_record()
114114
return self._handle_for_status(record)
115115
except Exception as exc:
116-
raise IdempotencyPersistenceLayerError("Failed to save in progress record to idempotency store") from exc
116+
raise IdempotencyPersistenceLayerError(
117+
"Failed to save in progress record to idempotency store", exc
118+
) from exc
117119

118120
return self._get_function_response()
119121

@@ -161,7 +163,7 @@ def _get_idempotency_record(self) -> DataRecord:
161163
# Wrap remaining unhandled exceptions with IdempotencyPersistenceLayerError to ease exception handling for
162164
# clients
163165
except Exception as exc:
164-
raise IdempotencyPersistenceLayerError("Failed to get record from idempotency store") from exc
166+
raise IdempotencyPersistenceLayerError("Failed to get record from idempotency store", exc) from exc
165167

166168
return data_record
167169

@@ -214,7 +216,7 @@ def _get_function_response(self):
214216
self.persistence_store.delete_record(data=self.data, exception=handler_exception)
215217
except Exception as delete_exception:
216218
raise IdempotencyPersistenceLayerError(
217-
"Failed to delete record from idempotency store"
219+
"Failed to delete record from idempotency store", delete_exception
218220
) from delete_exception
219221
raise
220222

@@ -223,7 +225,7 @@ def _get_function_response(self):
223225
self.persistence_store.save_success(data=self.data, result=response)
224226
except Exception as save_exception:
225227
raise IdempotencyPersistenceLayerError(
226-
"Failed to update record state to success in idempotency store"
228+
"Failed to update record state to success in idempotency store", save_exception
227229
) from save_exception
228230

229231
return response

aws_lambda_powertools/utilities/idempotency/exceptions.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,71 @@
33
"""
44

55

6-
class IdempotencyItemAlreadyExistsError(Exception):
6+
from typing import Optional, Union
7+
8+
9+
class BaseError(Exception):
10+
"""
11+
Base error class that overwrites the way exception and extra information is printed.
12+
See https://github.com/awslabs/aws-lambda-powertools-python/issues/1772
13+
"""
14+
15+
def __init__(self, *args: Optional[Union[str, Exception]]):
16+
self.message = str(args[0]) if args else ""
17+
self.details = "".join(str(arg) for arg in args[1:]) if args[1:] else None
18+
19+
def __str__(self):
20+
"""
21+
Return all arguments formatted or original message
22+
"""
23+
if self.message and self.details:
24+
return f"{self.message} - ({self.details})"
25+
return self.message
26+
27+
28+
class IdempotencyItemAlreadyExistsError(BaseError):
729
"""
830
Item attempting to be inserted into persistence store already exists and is not expired
931
"""
1032

1133

12-
class IdempotencyItemNotFoundError(Exception):
34+
class IdempotencyItemNotFoundError(BaseError):
1335
"""
1436
Item does not exist in persistence store
1537
"""
1638

1739

18-
class IdempotencyAlreadyInProgressError(Exception):
40+
class IdempotencyAlreadyInProgressError(BaseError):
1941
"""
2042
Execution with idempotency key is already in progress
2143
"""
2244

2345

24-
class IdempotencyInvalidStatusError(Exception):
46+
class IdempotencyInvalidStatusError(BaseError):
2547
"""
2648
An invalid status was provided
2749
"""
2850

2951

30-
class IdempotencyValidationError(Exception):
52+
class IdempotencyValidationError(BaseError):
3153
"""
3254
Payload does not match stored idempotency record
3355
"""
3456

3557

36-
class IdempotencyInconsistentStateError(Exception):
58+
class IdempotencyInconsistentStateError(BaseError):
3759
"""
3860
State is inconsistent across multiple requests to persistence store
3961
"""
4062

4163

42-
class IdempotencyPersistenceLayerError(Exception):
64+
class IdempotencyPersistenceLayerError(BaseError):
4365
"""
4466
Unrecoverable error from the data store
4567
"""
4668

4769

48-
class IdempotencyKeyError(Exception):
70+
class IdempotencyKeyError(BaseError):
4971
"""
5072
Payload does not contain an idempotent key
5173
"""

tests/functional/idempotency/test_idempotency.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,7 +1070,19 @@ def test_idempotent_lambda_save_inprogress_error(persistence_store: DynamoDBPers
10701070
# GIVEN a miss configured persistence layer
10711071
# like no table was created for the idempotency persistence layer
10721072
stubber = stub.Stubber(persistence_store.table.meta.client)
1073-
stubber.add_client_error("put_item", "ResourceNotFoundException")
1073+
service_error_code = "ResourceNotFoundException"
1074+
service_message = "Custom message"
1075+
1076+
exception_message = "Failed to save in progress record to idempotency store"
1077+
exception_details = (
1078+
f"An error occurred ({service_error_code}) when calling the PutItem operation: {service_message}"
1079+
)
1080+
1081+
stubber.add_client_error(
1082+
"put_item",
1083+
service_error_code,
1084+
service_message,
1085+
)
10741086
stubber.activate()
10751087

10761088
@idempotent(persistence_store=persistence_store)
@@ -1083,9 +1095,13 @@ def lambda_handler(event, context):
10831095
lambda_handler({}, lambda_context)
10841096

10851097
# THEN idempotent should raise an IdempotencyPersistenceLayerError
1098+
# AND append downstream exception details
10861099
stubber.assert_no_pending_responses()
10871100
stubber.deactivate()
1088-
assert "Failed to save in progress record to idempotency store" == e.value.args[0]
1101+
assert exception_message == e.value.args[0]
1102+
assert isinstance(e.value.args[1], Exception)
1103+
assert exception_details in e.value.args[1].args
1104+
assert f"{exception_message} - ({exception_details})" in str(e.value)
10891105

10901106

10911107
def test_handler_raise_idempotency_key_error(persistence_store: DynamoDBPersistenceLayer, lambda_context):

0 commit comments

Comments
 (0)