Skip to content

Commit b668a42

Browse files
committed
feat: Add a callback to be called on transaction failure
1 parent 1e37ba6 commit b668a42

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

src/Illuminate/Database/Concerns/ManagesTransactions.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ trait ManagesTransactions
2020
*
2121
* @throws \Throwable
2222
*/
23-
public function transaction(Closure $callback, $attempts = 1)
23+
public function transaction(Closure $callback, $attempts = 1, ?Closure $onFailureCallback = null)
2424
{
2525
for ($currentAttempt = 1; $currentAttempt <= $attempts; $currentAttempt++) {
2626
$this->beginTransaction();
@@ -37,7 +37,7 @@ public function transaction(Closure $callback, $attempts = 1)
3737
// exception back out, and let the developer handle an uncaught exception.
3838
catch (Throwable $e) {
3939
$this->handleTransactionException(
40-
$e, $currentAttempt, $attempts
40+
$e, $currentAttempt, $attempts, $onFailureCallback
4141
);
4242

4343
continue;
@@ -78,11 +78,12 @@ public function transaction(Closure $callback, $attempts = 1)
7878
* @param \Throwable $e
7979
* @param int $currentAttempt
8080
* @param int $maxAttempts
81+
* @param Closure|null $onFailureCallback
8182
* @return void
8283
*
8384
* @throws \Throwable
8485
*/
85-
protected function handleTransactionException(Throwable $e, $currentAttempt, $maxAttempts)
86+
protected function handleTransactionException(Throwable $e, $currentAttempt, $maxAttempts, ?Closure $onFailureCallback)
8687
{
8788
// On a deadlock, MySQL rolls back the entire transaction so we can't just
8889
// retry the query. We have to throw this exception all the way out and
@@ -108,6 +109,10 @@ protected function handleTransactionException(Throwable $e, $currentAttempt, $ma
108109
return;
109110
}
110111

112+
if ($onFailureCallback !== null) {
113+
$onFailureCallback($e);
114+
}
115+
111116
throw $e;
112117
}
113118

tests/Integration/Database/DatabaseTransactionsTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,42 @@ public function testTransactionsDoNotAffectDifferentConnections()
105105
$this->assertTrue($secondObject->ran);
106106
$this->assertFalse($thirdObject->ran);
107107
}
108+
109+
public function testOnErrorCallbackIsCalled()
110+
{
111+
$executed = false;
112+
try {
113+
DB::transaction(function () {
114+
throw new \Exception;
115+
}, 1, function () use (&$executed) {
116+
$executed = true;
117+
});
118+
} catch (\Throwable) {
119+
// Ignore the exception
120+
}
121+
122+
$this->assertTrue($executed);
123+
}
124+
125+
public function testOnErrorCallbackIsCalledWithDeadlockRetry()
126+
{
127+
$executed = false;
128+
$attempts = 0;
129+
130+
try {
131+
DB::transaction(function () use (&$attempts) {
132+
$attempts += 1;
133+
throw new \Exception('has been chosen as the deadlock victim');
134+
}, 3, function () use (&$executed) {
135+
$executed = true;
136+
});
137+
} catch (\Throwable) {
138+
// Ignore the exception
139+
}
140+
141+
$this->assertSame(3, $attempts);
142+
$this->assertTrue($executed);
143+
}
108144
}
109145

110146
class TestObjectForTransactions

0 commit comments

Comments
 (0)