|
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