Skip to content

Commit fca82d7

Browse files
authored
fix: Handle lazy initialization by Zappa (#102)
1 parent 9b0e343 commit fca82d7

File tree

2 files changed

+74
-30
lines changed

2 files changed

+74
-30
lines changed

sentry_sdk/integrations/aws_lambda.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from sentry_sdk.integrations._wsgi import _filter_headers
1313

1414
import __main__ as lambda_bootstrap
15+
import runtime as lambda_runtime
1516

1617

1718
class AwsLambdaIntegration(Integration):
@@ -46,20 +47,30 @@ def sentry_handler(event, context, *args, **kwargs):
4647

4748
hub.capture_event(event, hint=hint)
4849
reraise(*exc_info)
49-
finally:
50-
client = hub.client
51-
# Flush out the event queue before AWS kills the
52-
# process. This is not threadsafe.
53-
if client is not None:
54-
# make new transport with empty queue
55-
new_transport = client.transport.copy()
56-
client.close()
57-
client.transport = new_transport
5850

5951
return sentry_handler
6052

6153
lambda_bootstrap.make_final_handler = sentry_make_final_handler
6254

55+
old_report_done = lambda_runtime.report_done
56+
57+
def sentry_report_done(*args, **kwargs):
58+
with capture_internal_exceptions():
59+
hub = Hub.current
60+
if hub is not None:
61+
client = hub.client
62+
# Flush out the event queue before AWS kills the
63+
# process. This is not threadsafe.
64+
if client is not None:
65+
# make new transport with empty queue
66+
new_transport = client.transport.copy()
67+
client.close()
68+
client.transport = new_transport
69+
70+
return old_report_done(*args, **kwargs)
71+
72+
lambda_runtime.report_done = sentry_report_done
73+
6374

6475
def _make_request_event_processor(aws_event, aws_context):
6576
def event_processor(event, hint):

tests/integrations/aws_lambda/test_aws.py

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
import subprocess
66
import sys
77
import uuid
8+
from textwrap import dedent
89

910
import pytest
1011

1112
boto3 = pytest.importorskip("boto3")
1213

13-
LAMBDA_TEMPLATE = """
14+
LAMBDA_PRELUDE = """
1415
from __future__ import print_function
1516
1617
from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration
@@ -31,16 +32,12 @@ def shutdown(self, timeout, callback=None):
3132
for event in self._queue:
3233
print("EVENT:", json.dumps(event))
3334
34-
sentry_sdk.init(
35-
"http://[email protected]/2",
36-
transport=TestTransport(),
37-
integrations=[AwsLambdaIntegration()],
38-
**{extra_init_args}
39-
)
40-
41-
42-
def test_handler(event, context):
43-
{code}
35+
def init_sdk(**extra_init_args):
36+
sentry_sdk.init(
37+
transport=TestTransport(),
38+
integrations=[AwsLambdaIntegration()],
39+
**extra_init_args
40+
)
4441
"""
4542

4643

@@ -59,17 +56,13 @@ def lambda_client():
5956

6057
@pytest.fixture(params=["python3.6", "python2.7"])
6158
def run_lambda_function(tmpdir, lambda_client, request, assert_semaphore_acceptance):
62-
def inner(lambda_body, payload, extra_init_args=None):
59+
def inner(code, payload):
60+
runtime = request.param
6361
tmpdir.ensure_dir("lambda_tmp").remove()
6462
tmp = tmpdir.ensure_dir("lambda_tmp")
6563

6664
# https://docs.aws.amazon.com/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html
67-
tmp.join("test_lambda.py").write(
68-
LAMBDA_TEMPLATE.format(
69-
code="\n".join(" " + x.strip() for x in lambda_body.splitlines()),
70-
extra_init_args=repr(extra_init_args or {}),
71-
)
72-
)
65+
tmp.join("test_lambda.py").write(code)
7366
tmp.join("setup.cfg").write("[install]\nprefix=")
7467
subprocess.check_call([sys.executable, "setup.py", "sdist", "-d", str(tmpdir)])
7568
subprocess.check_call("pip install ../*.tar.gz -t .", cwd=str(tmp), shell=True)
@@ -79,7 +72,7 @@ def inner(lambda_body, payload, extra_init_args=None):
7972

8073
lambda_client.create_function(
8174
FunctionName=fn_name,
82-
Runtime=request.param,
75+
Runtime=runtime,
8376
Role=os.environ["AWS_IAM_ROLE"],
8477
Handler="test_lambda.test_handler",
8578
Code={"ZipFile": tmpdir.join("ball.zip").read(mode="rb")},
@@ -116,7 +109,15 @@ def delete_function():
116109

117110
def test_basic(run_lambda_function):
118111
events, response = run_lambda_function(
119-
'raise Exception("something went wrong")\n', b'{"foo": "bar"}'
112+
LAMBDA_PRELUDE
113+
+ dedent(
114+
"""
115+
init_sdk()
116+
def test_handler(event, context):
117+
raise Exception("something went wrong")
118+
"""
119+
),
120+
b'{"foo": "bar"}',
120121
)
121122

122123
assert response["FunctionError"] == "Unhandled"
@@ -139,9 +140,41 @@ def test_basic(run_lambda_function):
139140
assert event["extra"]["lambda"]["function_name"].startswith("test_function_")
140141

141142

143+
def test_initialization_order(run_lambda_function):
144+
"""Zappa lazily imports our code, so by the time we monkeypatch the handler
145+
as seen by AWS already runs. At this point at least draining the queue
146+
should work."""
147+
148+
events, _response = run_lambda_function(
149+
LAMBDA_PRELUDE
150+
+ dedent(
151+
"""
152+
def test_handler(event, context):
153+
init_sdk()
154+
sentry_sdk.capture_exception(Exception("something went wrong"))
155+
"""
156+
),
157+
b'{"foo": "bar"}',
158+
)
159+
160+
event, = events
161+
assert event["level"] == "error"
162+
exception, = event["exception"]["values"]
163+
assert exception["type"] == "Exception"
164+
assert exception["value"] == "something went wrong"
165+
166+
142167
def test_request_data(run_lambda_function):
143168
events, _response = run_lambda_function(
144-
'sentry_sdk.capture_message("hi")\nreturn "ok"',
169+
LAMBDA_PRELUDE
170+
+ dedent(
171+
"""
172+
init_sdk()
173+
def test_handler(event, context):
174+
sentry_sdk.capture_message("hi")
175+
return "ok"
176+
"""
177+
),
145178
payload=b"""
146179
{
147180
"resource": "/asd",

0 commit comments

Comments
 (0)