Skip to content

Commit 0558edd

Browse files
authored
fix: Fix concurrency issues in sanic (getsentry#123)
* fix: Fix concurrency issues in sanic * test: Some extra assertions
1 parent 2b0c68b commit 0558edd

File tree

3 files changed

+63
-15
lines changed

3 files changed

+63
-15
lines changed

sentry_sdk/integrations/sanic.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,19 @@ def setup_once():
3636
async def sentry_handle_request(self, request, *args, **kwargs):
3737
hub = Hub.current
3838
if hub.get_integration(SanicIntegration) is None:
39-
response = old_handle_request(self, request, *args, **kwargs)
40-
else:
41-
weak_request = weakref.ref(request)
39+
return old_handle_request(self, request, *args, **kwargs)
40+
41+
weak_request = weakref.ref(request)
4242

43-
with hub.push_scope() as scope:
43+
with Hub(hub) as hub:
44+
with hub.configure_scope() as scope:
4445
scope.add_event_processor(_make_request_processor(weak_request))
45-
response = old_handle_request(self, request, *args, **kwargs)
46-
if isawaitable(response):
47-
response = await response
4846

49-
return response
47+
response = old_handle_request(self, request, *args, **kwargs)
48+
if isawaitable(response):
49+
response = await response
50+
51+
return response
5052

5153
Sanic.handle_request = sentry_handle_request
5254

tests/integrations/sanic/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import pytest
2+
3+
sanic = pytest.importorskip("sanic")

tests/integrations/sanic/test_sanic.py

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import pytest
1+
import random
2+
import asyncio
23

3-
sanic = pytest.importorskip("sanic")
4+
import pytest
45

5-
from sentry_sdk import capture_message
6+
from sentry_sdk import capture_message, configure_scope
67
from sentry_sdk.integrations.sanic import SanicIntegration
78

8-
from sanic import Sanic, response
9+
from sanic import Sanic, request, response
910

1011

1112
@pytest.fixture
@@ -67,7 +68,7 @@ def myerror(request):
6768
assert exception["type"] == "ValueError"
6869
assert exception["value"] == "oh no"
6970
assert any(
70-
frame["filename"] == "test_sanic.py"
71+
frame["filename"].endswith("test_sanic.py")
7172
for frame in exception["stacktrace"]["frames"]
7273
)
7374

@@ -92,13 +93,55 @@ def myhandler(request, exception):
9293
exception, = event1["exception"]["values"]
9394
assert exception["type"] == "ValueError"
9495
assert any(
95-
frame["filename"] == "test_sanic.py"
96+
frame["filename"].endswith("test_sanic.py")
9697
for frame in exception["stacktrace"]["frames"]
9798
)
9899

99100
exception, = event2["exception"]["values"]
100101
assert exception["type"] == "ZeroDivisionError"
101102
assert any(
102-
frame["filename"] == "test_sanic.py"
103+
frame["filename"].endswith("test_sanic.py")
103104
for frame in exception["stacktrace"]["frames"]
104105
)
106+
107+
108+
def test_concurrency(sentry_init, app):
109+
sentry_init(integrations=[SanicIntegration()])
110+
111+
@app.route("/context-check/<i>")
112+
async def context_check(request, i):
113+
with configure_scope() as scope:
114+
scope.set_tag("i", i)
115+
116+
await asyncio.sleep(random.random())
117+
118+
with configure_scope() as scope:
119+
assert scope._tags["i"] == i
120+
121+
return response.text("ok")
122+
123+
async def task(i):
124+
responses = []
125+
126+
await app.handle_request(
127+
request.Request(
128+
url_bytes=f"http://localhost/context-check/{i}".encode("ascii"),
129+
headers={},
130+
version="1.1",
131+
method="GET",
132+
transport=None,
133+
),
134+
write_callback=responses.append,
135+
stream_callback=responses.append,
136+
)
137+
138+
r, = responses
139+
assert r.status == 200
140+
141+
async def runner():
142+
await asyncio.gather(*(task(i) for i in range(1000)))
143+
144+
asyncio.run(runner())
145+
146+
with configure_scope() as scope:
147+
assert not scope._tags

0 commit comments

Comments
 (0)