Skip to content

Commit 85ba9a5

Browse files
committed
Check for long running transaction on span exit.
1 parent d09babd commit 85ba9a5

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

sentry_sdk/integrations/wsgi.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,6 @@ def __call__(self, status, response_headers, exc_info=None): # type: ignore
4545
pass
4646

4747

48-
MAX_TRANSACTION_DURATION_SECONDS = 5 * 60
49-
50-
5148
_wsgi_middleware_applied = ContextVar("sentry_wsgi_middleware_applied")
5249

5350

sentry_sdk/tracing.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
nanosecond_time,
1414
)
1515

16+
MAX_TRANSACTION_DURATION_SECONDS = 5 * 60
17+
1618
from typing import TYPE_CHECKING
1719

1820
if TYPE_CHECKING:
@@ -377,7 +379,10 @@ def __exit__(self, ty, value, tb):
377379

378380
scope, old_span = self._context_manager_state
379381
del self._context_manager_state
382+
380383
self.finish(scope)
384+
self.prune_transaction()
385+
381386
scope.span = old_span
382387

383388
@property
@@ -651,6 +656,30 @@ def finish(self, scope=None, end_timestamp=None):
651656

652657
return None
653658

659+
def prune_transaction(self, scope=None):
660+
# type: (Optional[sentry_sdk.Scope]) -> None
661+
if (
662+
self.containing_transaction
663+
and self.containing_transaction.timestamp is not None
664+
):
665+
# transaction already finished, nothing to do
666+
return
667+
668+
trx = self.containing_transaction
669+
if trx is None or self is trx:
670+
return
671+
672+
transaction_duration = (
673+
datetime.now(timezone.utc) - trx.start_timestamp
674+
).total_seconds()
675+
676+
if transaction_duration > MAX_TRANSACTION_DURATION_SECONDS:
677+
logger.debug(
678+
"Finishing Transaction because it is running longer the maximum allowed duration (%ss)",
679+
MAX_TRANSACTION_DURATION_SECONDS,
680+
)
681+
trx.__exit__(None, None, None)
682+
654683
def to_json(self):
655684
# type: () -> Dict[str, Any]
656685
"""Returns a JSON-compatible representation of the span."""

tests/integrations/wsgi/test_wsgi.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -500,20 +500,23 @@ def dogpark(environ, start_response):
500500

501501

502502
def test_long_running_transaction_finished(sentry_init, capture_events):
503-
# we allow transactions to be 0.5 seconds as a maximum
504-
new_max_duration = 0.5
503+
# we allow transactions to be 1 seconds as a maximum
504+
new_max_duration = 1
505505

506506
with mock.patch.object(
507-
sentry_sdk.integrations.wsgi,
507+
sentry_sdk.tracing,
508508
"MAX_TRANSACTION_DURATION_SECONDS",
509509
new_max_duration,
510510
):
511511

512512
def generate_content():
513513
# This response will take 1.5 seconds to generate
514514
for _ in range(15):
515-
time.sleep(0.1)
516-
yield "ok"
515+
with sentry_sdk.start_span(
516+
op="generate_content", name="generate_content {_}"
517+
):
518+
time.sleep(0.1)
519+
yield "ok"
517520

518521
def long_running_app(environ, start_response):
519522
start_response("200 OK", [])
@@ -534,6 +537,8 @@ def long_running_app(environ, start_response):
534537
datetime_from_isoformat(transaction["timestamp"])
535538
- datetime_from_isoformat(transaction["start_timestamp"])
536539
).total_seconds()
540+
537541
assert (
538-
transaction_duration <= new_max_duration * 1.02
539-
) # we allow 2% margin for processing the request
542+
transaction_duration
543+
<= new_max_duration * 1.05 # we allow 5% margin for processing the request
544+
), "Long running transaction has not been finished after a set maximum duration"

0 commit comments

Comments
 (0)