|
1 | 1 | from datetime import datetime, timezone
|
2 | 2 | import sys
|
3 | 3 | from functools import partial
|
| 4 | +from threading import Timer |
4 | 5 |
|
5 | 6 | import sentry_sdk
|
6 | 7 | from sentry_sdk._werkzeug import get_host, _get_headers
|
@@ -46,7 +47,7 @@ def __call__(self, status, response_headers, exc_info=None): # type: ignore
|
46 | 47 | pass
|
47 | 48 |
|
48 | 49 |
|
49 |
| -MAX_TRANSACTION_DURATION_MINUTES = 5 |
| 50 | +MAX_TRANSACTION_DURATION_SECONDS = 5 * 60 |
50 | 51 |
|
51 | 52 |
|
52 | 53 | _wsgi_middleware_applied = ContextVar("sentry_wsgi_middleware_applied")
|
@@ -128,7 +129,12 @@ def __call__(self, environ, start_response):
|
128 | 129 | transaction,
|
129 | 130 | custom_sampling_context={"wsgi_environ": environ},
|
130 | 131 | ).__enter__()
|
131 |
| - |
| 132 | + timer = Timer( |
| 133 | + MAX_TRANSACTION_DURATION_SECONDS, |
| 134 | + finish_long_running_transaction, |
| 135 | + args=(current_scope, scope), |
| 136 | + ) |
| 137 | + timer.start() |
132 | 138 | try:
|
133 | 139 | response = self.app(
|
134 | 140 | environ,
|
@@ -235,6 +241,25 @@ def _capture_exception(exc_info=None):
|
235 | 241 | return exc_info
|
236 | 242 |
|
237 | 243 |
|
| 244 | +def finish_long_running_transaction(current_scope, isolation_scope): |
| 245 | + # type: (sentry_sdk.scope.Scope, sentry_sdk.scope.Scope) -> None |
| 246 | + """ |
| 247 | + Make sure we don't keep transactions open for too long. |
| 248 | + Triggered after MAX_TRANSACTION_DURATION_SECONDS have passed. |
| 249 | + """ |
| 250 | + try: |
| 251 | + transaction_duration = ( |
| 252 | + datetime.now(timezone.utc) - current_scope.transaction.start_timestamp |
| 253 | + ).total_seconds() |
| 254 | + if transaction_duration > MAX_TRANSACTION_DURATION_SECONDS: |
| 255 | + with use_isolation_scope(isolation_scope): |
| 256 | + with use_scope(current_scope): |
| 257 | + finish_running_transaction() |
| 258 | + except AttributeError: |
| 259 | + # transaction is not there anymore |
| 260 | + pass |
| 261 | + |
| 262 | + |
238 | 263 | class _ScopedResponse:
|
239 | 264 | """
|
240 | 265 | Use separate scopes for each response chunk.
|
@@ -276,17 +301,6 @@ def __iter__(self):
|
276 | 301 |
|
277 | 302 | yield chunk
|
278 | 303 |
|
279 |
| - # Finish long running transactions at some point |
280 |
| - try: |
281 |
| - transaction_duration = (datetime.now(timezone.utc) - self._current_scope.transaction.start_timestamp).total_seconds() / 60 |
282 |
| - if transaction_duration > MAX_TRANSACTION_DURATION_MINUTES: |
283 |
| - with use_isolation_scope(self._isolation_scope): |
284 |
| - with use_scope(self._current_scope): |
285 |
| - finish_running_transaction(self._current_scope) |
286 |
| - except AttributeError: |
287 |
| - # transaction is not there anymore |
288 |
| - pass |
289 |
| - |
290 | 304 | finally:
|
291 | 305 | with use_isolation_scope(self._isolation_scope):
|
292 | 306 | with use_scope(self._current_scope):
|
|
0 commit comments