-
Notifications
You must be signed in to change notification settings - Fork 420
Exception handling in batch processing doesn't work as expected #275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi @pcolazurdo thanks for raising! I just tried to reproduce this with a minimal Lambda using a record handler that throws different exceptions, and this is the logged output I get: 1611349258953,"[ERROR] SQSBatchProcessingError: [ZeroDivisionError('division by zero'), TypeError('can only concatenate str (not ""int"") to str'), ZeroDivisionError('division by zero'), TypeError('can only concatenate str (not ""int"") to str'), TypeError('can only concatenate str (not ""int"") to str'), TypeError('can only concatenate str (not ""int"") to str')]
Traceback (most recent call last):
File ""/opt/python/aws_lambda_powertools/logging/logger.py"", line 270, in decorate
return lambda_handler(event, context)
File ""/opt/python/aws_lambda_powertools/middleware_factory/factory.py"", line 133, in wrapper
response = middleware()
File ""/opt/python/aws_lambda_powertools/utilities/batch/sqs.py"", line 181, in sqs_batch_processor
processor.process()
File ""/opt/python/aws_lambda_powertools/utilities/batch/base.py"", line 58, in __exit__
self._clean()
File ""/opt/python/aws_lambda_powertools/utilities/batch/sqs.py"", line 126, in _clean
raise SQSBatchProcessingError(list(self.exceptions))"
1611349258968,"END RequestId: b34f1073-dd51-5db7-822a-48f6e26a197a" The first line in the log shows a list of the exceptions that were raised - can you confirm that you don't see this line without debug mode enabled? If its not being logged for you, I'll need some more details about your code / function configuration to help me reproduce it. If you need to log the tracebacks of individual errors which occur in the record handler, a quick solution would be to catch the exceptions and add a logging statement in your own code before re-raising (example below). We could also log the tracebacks one by one as they occur, but would probably want to implement that with a parameter defaulting to disabled. try:
do_something_with_record(record)
except Exception as exc:
logger.exception(exc)
raise |
@cakepietoast thanks for investigating this. I think your code reproduces the problem quite well. I'm copying mine just in case but in your traceback you can see that, while the list of Exception message is preserved, the actual location of the exception is lost. This is problematic for nested calls or a complex if then structures (among many others). You can see in this Traceback that it loses the information of where the exception actually happened as it should point to def
The code for this is: import json
# import os
# import boto3
# from aws_lambda_powertools.metrics import Metrics, MetricUnit
from aws_lambda_powertools.logging import Logger
from aws_lambda_powertools.tracing import Tracer
from aws_lambda_powertools.utilities.batch import PartialSQSProcessor
# from aws_lambda_powertools.logging.logger import set_package_logger
SERVICE = 'powertools_test'
# metrics = Metrics(service=SERVICE)
tracer = Tracer(service=SERVICE)
logger = Logger(service=SERVICE)
@tracer.capture_method
def process_request():
return {
"statusCode": 200,
"body": json.dumps({
'status': 'PageSaved',
'url': non_existant_var,
'crawledFile': non_existant_var
})
}
@tracer.capture_method
def record_handler(record):
# This will be called for each individual message from a batch
# It should raise an exception if the message was not processed successfully
try:
res = process_request()
return res
except Exception as e:
raise e
@logger.inject_lambda_context(log_event=True)
@tracer.capture_lambda_handler
def lambda_handler(event, context):
"""
"""
records = event["Records"]
processor = PartialSQSProcessor(suppress_exception=False)
with processor(records, record_handler) as proc:
result = proc.process() # Returns a list of all results from record_handler
logger.structure_logs(append=True, results=result)
return result Hope this helps, |
Gotcha, thanks for clarifying and providing the extra detail! Working on a solution for this now - would this be a reasonable format for the exception output? Traceback (most recent call last):
File "cause_batch_exceptions.py", line 60, in <module>
lambda_handler(event, {})
File "/tmp/aws-lambda-powertools-python/aws_lambda_powertools/middleware_factory/factory.py", line 133, in wrapper
response = middleware()
File "/tmp/aws-lambda-powertools-python/aws_lambda_powertools/utilities/batch/sqs.py", line 186, in sqs_batch_processor
processor.process()
File "/tmp/aws-lambda-powertools-python/aws_lambda_powertools/utilities/batch/base.py", line 58, in __exit__
self._clean()
File "/tmp/aws-lambda-powertools-python/aws_lambda_powertools/utilities/batch/sqs.py", line 127, in _clean
raise SQSBatchProcessingError(
aws_lambda_powertools.utilities.batch.exceptions.SQSBatchProcessingError: Not all records processed succesfully. 2 individual errors logged separately below.
Traceback (most recent call last):
File "/tmp/aws-lambda-powertools-python/aws_lambda_powertools/utilities/batch/sqs.py", line 94, in _process_record
result = self.handler(record)
File "cause_batch_exceptions.py", line 36, in record_handler
return aa
NameError: name 'aa' is not defined
Traceback (most recent call last):
File "/tmp/aws-lambda-powertools-python/aws_lambda_powertools/utilities/batch/sqs.py", line 94, in _process_record
result = self.handler(record)
File "cause_batch_exceptions.py", line 38, in record_handler
print(42/0)
ZeroDivisionError: division by zero |
Yes, that looks great!!!! |
Now available in 1.10.2!! Thanks for reporting and reproducing it @pcolazurdo !! and for @cakepietoast for the fix (As always) |
In this code:
If there is an exception raised inside the record_handler function, I expect the exception to be raised in the function and get some details about what caused the exception. The code in https://github.com/awslabs/aws-lambda-powertools-python/blob/e104bfb5dcedf7b52d4a7925ae446ff719b8c110/aws_lambda_powertools/utilities/batch/sqs.py#L126 tries to be smart about it and raise a list of all the exceptions in the batch, but this doesn't work as expected, as the Exception code is not smart enough to show a list of exceptions. The actual result looks like this:
What were you trying to accomplish?
Expected Behavior
I would except the Exception to be raised in a manner that all the exceptions are shown together.
Also, reviewing the code I see there is a fail_message property that doesn't seem to be exposed anywhere. Is there a plan for this? This may be very useful in some cases.
Current Behavior
Please review the Stack trace above
Possible Solution
I think re raising an exception may need some extra work like what is commented here: https://nedbatchelder.com/blog/200711/rethrowing_exceptions_in_python.html
Steps to Reproduce (for bugs)
Environment
The text was updated successfully, but these errors were encountered: