@@ -119,27 +119,26 @@ def __call__(self, environ, start_response):
119
119
origin = self .span_origin ,
120
120
)
121
121
122
- with (
123
- sentry_sdk .start_transaction (
122
+ if transaction is not None :
123
+ transaction = sentry_sdk .start_transaction (
124
124
transaction ,
125
125
custom_sampling_context = {"wsgi_environ" : environ },
126
126
)
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 ())
127
+ transaction .__enter__ ()
128
+
129
+ try :
130
+ response = self .app (
131
+ environ ,
132
+ partial (
133
+ _sentry_start_response , start_response , transaction
134
+ ),
135
+ )
136
+ except BaseException :
137
+ reraise (* _capture_exception ())
139
138
finally :
140
139
_wsgi_middleware_applied .set (False )
141
140
142
- return _ScopedResponse (scope , response )
141
+ return _ScopedResponse (scope , response , transaction )
143
142
144
143
145
144
def _sentry_start_response ( # type: ignore
@@ -234,12 +233,13 @@ class _ScopedResponse:
234
233
- WSGI servers streaming responses interleaved from the same thread
235
234
"""
236
235
237
- __slots__ = ("_response" , "_scope" )
236
+ __slots__ = ("_response" , "_scope" , "_transaction" )
238
237
239
- def __init__ (self , scope , response ):
240
- # type: (sentry_sdk.scope.Scope, Iterator[bytes]) -> None
238
+ def __init__ (self , scope , response , transaction ):
239
+ # type: (sentry_sdk.scope.Scope, Iterator[bytes], Optional[sentry_sdk.tracing.Transaction] ) -> None
241
240
self ._scope = scope
242
241
self ._response = response
242
+ self ._transaction = transaction
243
243
244
244
def __iter__ (self ):
245
245
# type: () -> Iterator[bytes]
@@ -261,6 +261,12 @@ def close(self):
261
261
with use_isolation_scope (self ._scope ):
262
262
try :
263
263
self ._response .close () # type: ignore
264
+ # Close the Sentry transaction
265
+ # This is done here to make sure the Transaction stays
266
+ # open until all streaming responses are done.
267
+ # Of course this here works also for non streaming responses.
268
+ if self ._transaction is not None :
269
+ self ._transaction .__exit__ (None , None , None )
264
270
except AttributeError :
265
271
pass
266
272
except BaseException :
0 commit comments