Skip to content

Commit 3d8445c

Browse files
authored
Revert "Fix spans for streaming responses in WSGI based frameworks (#3798)" (#3836)
This reverts commit da20623. (PR #3798) Having a timer thread on each request is too much overhead on high volume servers.
1 parent 6bd7e08 commit 3d8445c

File tree

6 files changed

+73
-270
lines changed

6 files changed

+73
-270
lines changed

sentry_sdk/integrations/wsgi.py

+41-94
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import sys
22
from functools import partial
3-
from threading import Timer
43

54
import sentry_sdk
65
from sentry_sdk._werkzeug import get_host, _get_headers
76
from sentry_sdk.api import continue_trace
87
from sentry_sdk.consts import OP
9-
from sentry_sdk.scope import should_send_default_pii, use_isolation_scope, use_scope
8+
from sentry_sdk.scope import should_send_default_pii
109
from sentry_sdk.integrations._wsgi_common import (
1110
DEFAULT_HTTP_METHODS_TO_CAPTURE,
1211
_filter_headers,
12+
nullcontext,
1313
)
1414
from sentry_sdk.sessions import track_session
15+
from sentry_sdk.scope import use_isolation_scope
1516
from sentry_sdk.tracing import Transaction, TRANSACTION_SOURCE_ROUTE
16-
from sentry_sdk.tracing_utils import finish_running_transaction
1717
from sentry_sdk.utils import (
1818
ContextVar,
1919
capture_internal_exceptions,
@@ -46,9 +46,6 @@ def __call__(self, status, response_headers, exc_info=None): # type: ignore
4646
pass
4747

4848

49-
MAX_TRANSACTION_DURATION_SECONDS = 5 * 60
50-
51-
5249
_wsgi_middleware_applied = ContextVar("sentry_wsgi_middleware_applied")
5350

5451

@@ -101,7 +98,6 @@ def __call__(self, environ, start_response):
10198
_wsgi_middleware_applied.set(True)
10299
try:
103100
with sentry_sdk.isolation_scope() as scope:
104-
current_scope = sentry_sdk.get_current_scope()
105101
with track_session(scope, session_mode="request"):
106102
with capture_internal_exceptions():
107103
scope.clear_breadcrumbs()
@@ -113,7 +109,6 @@ def __call__(self, environ, start_response):
113109
)
114110

115111
method = environ.get("REQUEST_METHOD", "").upper()
116-
117112
transaction = None
118113
if method in self.http_methods_to_capture:
119114
transaction = continue_trace(
@@ -124,43 +119,27 @@ def __call__(self, environ, start_response):
124119
origin=self.span_origin,
125120
)
126121

127-
timer = None
128-
if transaction is not None:
122+
with (
129123
sentry_sdk.start_transaction(
130124
transaction,
131125
custom_sampling_context={"wsgi_environ": environ},
132-
).__enter__()
133-
timer = Timer(
134-
MAX_TRANSACTION_DURATION_SECONDS,
135-
_finish_long_running_transaction,
136-
args=(current_scope, scope),
137126
)
138-
timer.start()
139-
140-
try:
141-
response = self.app(
142-
environ,
143-
partial(
144-
_sentry_start_response,
145-
start_response,
146-
transaction,
147-
),
148-
)
149-
except BaseException:
150-
exc_info = sys.exc_info()
151-
_capture_exception(exc_info)
152-
finish_running_transaction(current_scope, exc_info, timer)
153-
reraise(*exc_info)
154-
127+
if transaction is not None
128+
else nullcontext()
129+
):
130+
try:
131+
response = self.app(
132+
environ,
133+
partial(
134+
_sentry_start_response, start_response, transaction
135+
),
136+
)
137+
except BaseException:
138+
reraise(*_capture_exception())
155139
finally:
156140
_wsgi_middleware_applied.set(False)
157141

158-
return _ScopedResponse(
159-
response=response,
160-
current_scope=current_scope,
161-
isolation_scope=scope,
162-
timer=timer,
163-
)
142+
return _ScopedResponse(scope, response)
164143

165144

166145
def _sentry_start_response( # type: ignore
@@ -222,13 +201,13 @@ def get_client_ip(environ):
222201
return environ.get("REMOTE_ADDR")
223202

224203

225-
def _capture_exception(exc_info=None):
226-
# type: (Optional[ExcInfo]) -> ExcInfo
204+
def _capture_exception():
205+
# type: () -> ExcInfo
227206
"""
228207
Captures the current exception and sends it to Sentry.
229208
Returns the ExcInfo tuple to it can be reraised afterwards.
230209
"""
231-
exc_info = exc_info or sys.exc_info()
210+
exc_info = sys.exc_info()
232211
e = exc_info[1]
233212

234213
# SystemExit(0) is the only uncaught exception that is expected behavior
@@ -246,7 +225,7 @@ def _capture_exception(exc_info=None):
246225

247226
class _ScopedResponse:
248227
"""
249-
Use separate scopes for each response chunk.
228+
Users a separate scope for each response chunk.
250229
251230
This will make WSGI apps more tolerant against:
252231
- WSGI servers streaming responses from a different thread/from
@@ -255,54 +234,37 @@ class _ScopedResponse:
255234
- WSGI servers streaming responses interleaved from the same thread
256235
"""
257236

258-
__slots__ = ("_response", "_current_scope", "_isolation_scope", "_timer")
237+
__slots__ = ("_response", "_scope")
259238

260-
def __init__(
261-
self,
262-
response, # type: Iterator[bytes]
263-
current_scope, # type: sentry_sdk.scope.Scope
264-
isolation_scope, # type: sentry_sdk.scope.Scope
265-
timer=None, # type: Optional[Timer]
266-
):
267-
# type: (...) -> None
239+
def __init__(self, scope, response):
240+
# type: (sentry_sdk.scope.Scope, Iterator[bytes]) -> None
241+
self._scope = scope
268242
self._response = response
269-
self._current_scope = current_scope
270-
self._isolation_scope = isolation_scope
271-
self._timer = timer
272243

273244
def __iter__(self):
274245
# type: () -> Iterator[bytes]
275246
iterator = iter(self._response)
276247

277-
try:
278-
while True:
279-
with use_isolation_scope(self._isolation_scope):
280-
with use_scope(self._current_scope):
281-
try:
282-
chunk = next(iterator)
283-
except StopIteration:
284-
break
285-
except BaseException:
286-
reraise(*_capture_exception())
287-
288-
yield chunk
248+
while True:
249+
with use_isolation_scope(self._scope):
250+
try:
251+
chunk = next(iterator)
252+
except StopIteration:
253+
break
254+
except BaseException:
255+
reraise(*_capture_exception())
289256

290-
finally:
291-
with use_isolation_scope(self._isolation_scope):
292-
with use_scope(self._current_scope):
293-
finish_running_transaction(timer=self._timer)
257+
yield chunk
294258

295259
def close(self):
296260
# type: () -> None
297-
with use_isolation_scope(self._isolation_scope):
298-
with use_scope(self._current_scope):
299-
try:
300-
finish_running_transaction(timer=self._timer)
301-
self._response.close() # type: ignore
302-
except AttributeError:
303-
pass
304-
except BaseException:
305-
reraise(*_capture_exception())
261+
with use_isolation_scope(self._scope):
262+
try:
263+
self._response.close() # type: ignore
264+
except AttributeError:
265+
pass
266+
except BaseException:
267+
reraise(*_capture_exception())
306268

307269

308270
def _make_wsgi_event_processor(environ, use_x_forwarded_for):
@@ -346,18 +308,3 @@ def event_processor(event, hint):
346308
return event
347309

348310
return event_processor
349-
350-
351-
def _finish_long_running_transaction(current_scope, isolation_scope):
352-
# type: (sentry_sdk.scope.Scope, sentry_sdk.scope.Scope) -> None
353-
"""
354-
Make sure we don't keep transactions open for too long.
355-
Triggered after MAX_TRANSACTION_DURATION_SECONDS have passed.
356-
"""
357-
try:
358-
with use_isolation_scope(isolation_scope):
359-
with use_scope(current_scope):
360-
finish_running_transaction()
361-
except AttributeError:
362-
# transaction is not there anymore
363-
pass

sentry_sdk/tracing_utils.py

-18
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@
3636

3737
from types import FrameType
3838

39-
from sentry_sdk._types import ExcInfo
40-
from threading import Timer
41-
4239

4340
SENTRY_TRACE_REGEX = re.compile(
4441
"^[ \t]*" # whitespace
@@ -742,18 +739,3 @@ def get_current_span(scope=None):
742739

743740
if TYPE_CHECKING:
744741
from sentry_sdk.tracing import Span
745-
746-
747-
def finish_running_transaction(scope=None, exc_info=None, timer=None):
748-
# type: (Optional[sentry_sdk.Scope], Optional[ExcInfo], Optional[Timer]) -> None
749-
if timer is not None:
750-
timer.cancel()
751-
752-
current_scope = scope or sentry_sdk.get_current_scope()
753-
if current_scope.transaction is not None and hasattr(
754-
current_scope.transaction, "_context_manager_state"
755-
):
756-
if exc_info is not None:
757-
current_scope.transaction.__exit__(*exc_info)
758-
else:
759-
current_scope.transaction.__exit__(None, None, None)

0 commit comments

Comments
 (0)