@@ -47,13 +47,6 @@ class Middleware
47
47
*/
48
48
private $ continueAfterResponse ;
49
49
50
- /**
51
- * Whether the terminating callback has been registered.
52
- *
53
- * @var bool
54
- */
55
- private $ registeredTerminatingCallback = false ;
56
-
57
50
/**
58
51
* Whether a defined route was matched in the application.
59
52
*
@@ -115,22 +108,11 @@ public function terminate(Request $request, $response): void
115
108
}
116
109
117
110
if ($ this ->continueAfterResponse ) {
118
- // Ensure we do not register the terminating callback multiple times since there is no point in doing so
119
- if ($ this ->registeredTerminatingCallback ) {
120
- return ;
121
- }
122
-
123
- // We need to finish the transaction after the response has been sent to the client
124
- // so we register a terminating callback to do so, this allows us to also capture
125
- // spans that are created during the termination of the application like queue
126
- // dispatched using dispatch(...)->afterResponse(). This middleware is called
127
- // before the terminating callbacks so we are 99.9% sure to be the last one
128
- // to run except if another terminating callback is registered after ours.
129
- app ()->terminating (function () {
130
- $ this ->finishTransaction ();
131
- });
132
-
133
- $ this ->registeredTerminatingCallback = true ;
111
+ // Resolving the transaction finisher class will register the terminating callback
112
+ // which is responsible for calling `finishTransaction`. We have registered the
113
+ // class as a singleton to keep the state in the container and away from here
114
+ // this way we ensure the callback is only registered once even for Octane.
115
+ app (TransactionFinisher::class);
134
116
} else {
135
117
$ this ->finishTransaction ();
136
118
}
@@ -220,12 +202,12 @@ private function addAppBootstrapSpan(): ?Span
220
202
221
203
$ span = $ this ->transaction ->startChild ($ spanContextStart );
222
204
223
- // Consume the booted timestamp, because we don't want to report the bootstrap span more than once
224
- $ this ->bootedTimestamp = null ;
225
-
226
205
// Add more information about the bootstrap section if possible
227
206
$ this ->addBootDetailTimeSpans ($ span );
228
207
208
+ // Consume the booted timestamp, because we don't want to report the boot(strap) spans more than once
209
+ $ this ->bootedTimestamp = null ;
210
+
229
211
return $ span ;
230
212
}
231
213
@@ -250,7 +232,7 @@ private function hydrateResponseData(SymfonyResponse $response): void
250
232
$ this ->transaction ->setHttpStatus ($ response ->getStatusCode ());
251
233
}
252
234
253
- private function finishTransaction (): void
235
+ public function finishTransaction (): void
254
236
{
255
237
// We could end up multiple times here since we register a terminating callback so
256
238
// double check if we have a transaction before trying to finish it since it could
0 commit comments