Skip to content

Commit d2c44c7

Browse files
committed
Finish long running transactions at some point.
1 parent c612326 commit d2c44c7

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

sentry_sdk/integrations/wsgi.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from datetime import datetime, timezone
12
import sys
23
from functools import partial
34

@@ -45,6 +46,9 @@ def __call__(self, status, response_headers, exc_info=None): # type: ignore
4546
pass
4647

4748

49+
MAX_TRANSACTION_DURATION_MINUTES = 5
50+
51+
4852
_wsgi_middleware_applied = ContextVar("sentry_wsgi_middleware_applied")
4953

5054

@@ -272,6 +276,17 @@ def __iter__(self):
272276

273277
yield chunk
274278

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+
275290
finally:
276291
with use_isolation_scope(self._isolation_scope):
277292
with use_scope(self._current_scope):

tests/integrations/wsgi/test_wsgi.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import time
12
from collections import Counter
23
from unittest import mock
34

45
import pytest
6+
from sentry_sdk.utils import datetime_from_isoformat
57
from werkzeug.test import Client
68

79
import sentry_sdk
@@ -495,3 +497,33 @@ def dogpark(environ, start_response):
495497
(event,) = events
496498

497499
assert event["contexts"]["trace"]["origin"] == "auto.dogpark.deluxe"
500+
501+
502+
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 / 60
505+
506+
with mock.patch.object(sentry_sdk.integrations.wsgi, "MAX_TRANSACTION_DURATION_MINUTES", new_max_duration):
507+
def generate_content():
508+
# This response will take 1.5 seconds to generate
509+
for _ in range(15):
510+
time.sleep(0.1)
511+
yield "ok"
512+
513+
def long_running_app(environ, start_response):
514+
start_response("200 OK", [])
515+
return generate_content()
516+
517+
sentry_init(send_default_pii=True, traces_sample_rate=1.0)
518+
app = SentryWsgiMiddleware(long_running_app)
519+
520+
events = capture_events()
521+
522+
client = Client(app)
523+
response = client.get("/")
524+
_ = response.get_data()
525+
526+
(transaction,) = events
527+
528+
transaction_duration = (datetime_from_isoformat(transaction["timestamp"]) - datetime_from_isoformat(transaction["start_timestamp"])).total_seconds() / 60
529+
assert transaction_duration <= new_max_duration * 1.05 # we allow 2% error margin for processing the request

0 commit comments

Comments
 (0)