Skip to content

Commit 5e90ab5

Browse files
authored
Prevent registering terminating callback multiple times and incorrectly trying to finish transaction (#717)
1 parent 42de0d2 commit 5e90ab5

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Changelog
22

3+
## 3.5.1
4+
5+
The Sentry SDK team is happy to announce the immediate availability of Sentry Laravel SDK v3.5.1.
6+
7+
### Bug Fixes
8+
9+
- Prevent registering terminating callback multiple times and guard against finishing already finished transactions [(#717)](https://github.com/getsentry/sentry-laravel/pull/717)
10+
11+
This fixes the `Call to a member function finish() on null` that could occur when using long running processes like on the CLI or with Laravel Octane.
12+
313
## 3.5.0
414

515
The Sentry SDK team is happy to announce the immediate availability of Sentry Laravel SDK v3.5.0.

src/Sentry/Laravel/Tracing/Middleware.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ class Middleware
4343
*/
4444
private $app;
4545

46+
/**
47+
* Whether the terminating callback has been registered.
48+
*
49+
* @var bool
50+
*/
51+
private $registeredTerminatingCallback = false;
52+
4653
/**
4754
* Construct the Sentry tracing middleware.
4855
*
@@ -102,6 +109,11 @@ public function terminate(Request $request, $response): void
102109
if ($this->app === null) {
103110
$this->finishTransaction();
104111
} else {
112+
// Ensure we do not register the terminating callback multiple times since there is no point in doing so
113+
if ($this->registeredTerminatingCallback) {
114+
return;
115+
}
116+
105117
// We need to finish the transaction after the response has been sent to the client
106118
// so we register a terminating callback to do so, this allows us to also capture
107119
// spans that are created during the termination of the application like queue
@@ -111,6 +123,8 @@ public function terminate(Request $request, $response): void
111123
$this->app->terminating(function () {
112124
$this->finishTransaction();
113125
});
126+
127+
$this->registeredTerminatingCallback = true;
114128
}
115129
}
116130

@@ -223,6 +237,13 @@ private function hydrateResponseData(SymfonyResponse $response): void
223237

224238
private function finishTransaction(): void
225239
{
240+
// We could end up multiple times here since we register a terminating callback so
241+
// double check if we have a transaction before trying to finish it since it could
242+
// have already been finished in between being registered and being executed again
243+
if ($this->transaction === null) {
244+
return;
245+
}
246+
226247
// Make sure we set the transaction and not have a child span in the Sentry SDK
227248
// If the transaction is not on the scope during finish, the trace.context is wrong
228249
SentrySdk::getCurrentHub()->setSpan($this->transaction);

0 commit comments

Comments
 (0)