Skip to content

Commit bd40404

Browse files
committed
Raise all init errors in init instead of suppressing them until the fist
invoke
1 parent dc83706 commit bd40404

File tree

2 files changed

+21
-70
lines changed

2 files changed

+21
-70
lines changed

awslambdaric/bootstrap.py

+13-18
Original file line numberDiff line numberDiff line change
@@ -37,36 +37,30 @@ def _get_handler(handler):
3737
try:
3838
(modname, fname) = handler.rsplit(".", 1)
3939
except ValueError as e:
40-
fault = FaultException(
40+
raise FaultException(
4141
FaultException.MALFORMED_HANDLER_NAME,
4242
"Bad handler '{}': {}".format(handler, str(e)),
4343
)
44-
return make_fault_handler(fault)
4544

4645
try:
4746
if modname.split(".")[0] in sys.builtin_module_names:
48-
fault = FaultException(
47+
raise FaultException(
4948
FaultException.BUILT_IN_MODULE_CONFLICT,
5049
"Cannot use built-in module {} as a handler module".format(modname),
5150
)
52-
return make_fault_handler(fault)
5351
m = importlib.import_module(modname.replace("/", "."))
5452
except ImportError as e:
55-
fault = FaultException(
53+
raise FaultException(
5654
FaultException.IMPORT_MODULE_ERROR,
5755
"Unable to import module '{}': {}".format(modname, str(e)),
5856
)
59-
request_handler = make_fault_handler(fault)
60-
return request_handler
6157
except SyntaxError as e:
6258
trace = [' File "%s" Line %s\n %s' % (e.filename, e.lineno, e.text)]
63-
fault = FaultException(
59+
raise FaultException(
6460
FaultException.USER_CODE_SYNTAX_ERROR,
6561
"Syntax error in module '{}': {}".format(modname, str(e)),
6662
trace,
6763
)
68-
request_handler = make_fault_handler(fault)
69-
return request_handler
7064

7165
try:
7266
request_handler = getattr(m, fname)
@@ -76,15 +70,8 @@ def _get_handler(handler):
7670
"Handler '{}' missing on module '{}'".format(fname, modname),
7771
None,
7872
)
79-
request_handler = make_fault_handler(fault)
80-
return request_handler
81-
82-
83-
def make_fault_handler(fault):
84-
def result(*args):
8573
raise fault
86-
87-
return result
74+
return request_handler
8875

8976

9077
def make_error(
@@ -475,15 +462,23 @@ def run(app_root, handler, lambda_runtime_api_addr):
475462
lambda_runtime_client = LambdaRuntimeClient(
476463
lambda_runtime_api_addr, use_thread_for_polling_next
477464
)
465+
error_result = None
478466

479467
try:
480468
_setup_logging(_AWS_LAMBDA_LOG_FORMAT, _AWS_LAMBDA_LOG_LEVEL, log_sink)
481469
global _GLOBAL_AWS_REQUEST_ID
482470

483471
request_handler = _get_handler(handler)
472+
except FaultException as e:
473+
error_result = make_error(
474+
e.msg,
475+
e.exception_type,
476+
e.trace,
477+
)
484478
except Exception:
485479
error_result = build_fault_result(sys.exc_info(), None)
486480

481+
if error_result is not None:
487482
log_error(error_result, log_sink)
488483
lambda_runtime_client.post_init_error(to_json(error_result))
489484

tests/test_bootstrap.py

+8-52
Original file line numberDiff line numberDiff line change
@@ -603,43 +603,6 @@ def raise_exception_handler(json_input, lambda_context):
603603

604604
self.assertEqual(mock_stdout.getvalue(), error_logs)
605605

606-
# The order of patches matter. Using MagicMock resets sys.stdout to the default.
607-
@patch("importlib.import_module")
608-
@patch("sys.stdout", new_callable=StringIO)
609-
def test_handle_event_request_fault_exception_logging_syntax_error(
610-
self, mock_stdout, mock_import_module
611-
):
612-
try:
613-
eval("-")
614-
except SyntaxError as e:
615-
syntax_error = e
616-
617-
mock_import_module.side_effect = syntax_error
618-
619-
response_handler = bootstrap._get_handler("a.b")
620-
621-
bootstrap.handle_event_request(
622-
self.lambda_runtime,
623-
response_handler,
624-
"invoke_id",
625-
self.event_body,
626-
"application/json",
627-
{},
628-
{},
629-
"invoked_function_arn",
630-
0,
631-
bootstrap.StandardLogSink(),
632-
)
633-
error_logs = (
634-
lambda_unhandled_exception_warning_message
635-
+ f"[ERROR] Runtime.UserCodeSyntaxError: Syntax error in module 'a': {syntax_error}\r"
636-
)
637-
error_logs += "Traceback (most recent call last):\r"
638-
error_logs += '  File "<string>" Line 1\r'
639-
error_logs += "    -\n"
640-
641-
self.assertEqual(mock_stdout.getvalue(), error_logs)
642-
643606

644607
class TestXrayFault(unittest.TestCase):
645608
def test_make_xray(self):
@@ -717,10 +680,8 @@ def __eq__(self, other):
717680

718681
def test_get_event_handler_bad_handler(self):
719682
handler_name = "bad_handler"
720-
response_handler = bootstrap._get_handler(handler_name)
721683
with self.assertRaises(FaultException) as cm:
722-
response_handler()
723-
684+
response_handler = bootstrap._get_handler(handler_name)
724685
returned_exception = cm.exception
725686
self.assertEqual(
726687
self.FaultExceptionMatcher(
@@ -732,9 +693,8 @@ def test_get_event_handler_bad_handler(self):
732693

733694
def test_get_event_handler_import_error(self):
734695
handler_name = "no_module.handler"
735-
response_handler = bootstrap._get_handler(handler_name)
736696
with self.assertRaises(FaultException) as cm:
737-
response_handler()
697+
response_handler = bootstrap._get_handler(handler_name)
738698
returned_exception = cm.exception
739699
self.assertEqual(
740700
self.FaultExceptionMatcher(
@@ -757,10 +717,9 @@ def test_get_event_handler_syntax_error(self):
757717
filename_w_ext = os.path.basename(tmp_file.name)
758718
filename, _ = os.path.splitext(filename_w_ext)
759719
handler_name = "{}.syntax_error".format(filename)
760-
response_handler = bootstrap._get_handler(handler_name)
761720

762721
with self.assertRaises(FaultException) as cm:
763-
response_handler()
722+
response_handler = bootstrap._get_handler(handler_name)
764723
returned_exception = cm.exception
765724
self.assertEqual(
766725
self.FaultExceptionMatcher(
@@ -782,9 +741,8 @@ def test_get_event_handler_missing_error(self):
782741
filename_w_ext = os.path.basename(tmp_file.name)
783742
filename, _ = os.path.splitext(filename_w_ext)
784743
handler_name = "{}.my_handler".format(filename)
785-
response_handler = bootstrap._get_handler(handler_name)
786744
with self.assertRaises(FaultException) as cm:
787-
response_handler()
745+
response_handler = bootstrap._get_handler(handler_name)
788746
returned_exception = cm.exception
789747
self.assertEqual(
790748
self.FaultExceptionMatcher(
@@ -801,9 +759,8 @@ def test_get_event_handler_slash(self):
801759
response_handler()
802760

803761
def test_get_event_handler_build_in_conflict(self):
804-
response_handler = bootstrap._get_handler("sys.hello")
805762
with self.assertRaises(FaultException) as cm:
806-
response_handler()
763+
response_handler = bootstrap._get_handler("sys.hello")
807764
returned_exception = cm.exception
808765
self.assertEqual(
809766
self.FaultExceptionMatcher(
@@ -1452,9 +1409,8 @@ def test_set_log_level_with_dictConfig(self, mock_stderr, mock_stdout):
14521409

14531410

14541411
class TestBootstrapModule(unittest.TestCase):
1455-
@patch("awslambdaric.bootstrap.handle_event_request")
14561412
@patch("awslambdaric.bootstrap.LambdaRuntimeClient")
1457-
def test_run(self, mock_runtime_client, mock_handle_event_request):
1413+
def test_run(self, mock_runtime_client):
14581414
expected_app_root = "/tmp/test/app_root"
14591415
expected_handler = "app.my_test_handler"
14601416
expected_lambda_runtime_api_addr = "test_addr"
@@ -1467,12 +1423,12 @@ def test_run(self, mock_runtime_client, mock_handle_event_request):
14671423
MagicMock(),
14681424
]
14691425

1470-
with self.assertRaises(TypeError):
1426+
with self.assertRaises(SystemExit) as cm:
14711427
bootstrap.run(
14721428
expected_app_root, expected_handler, expected_lambda_runtime_api_addr
14731429
)
14741430

1475-
mock_handle_event_request.assert_called_once()
1431+
self.assertEqual(cm.exception.code, 1)
14761432

14771433
@patch(
14781434
"awslambdaric.bootstrap.LambdaLoggerHandler",

0 commit comments

Comments
 (0)