Skip to content

Commit 2ed3880

Browse files
committed
enh: Provide atomicRetry method to retry transactions if possible
Signed-off-by: Julius Härtl <jus@bitgrid.net>
1 parent c995428 commit 2ed3880

File tree

1 file changed

+37
-0
lines changed

1 file changed

+37
-0
lines changed

lib/public/AppFramework/Db/TTransactional.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@
2525

2626
namespace OCP\AppFramework\Db;
2727

28+
use OC\DB\Exceptions\DbalException;
2829
use OCP\DB\Exception;
2930
use OCP\IDBConnection;
3031
use Throwable;
32+
use function OCP\Log\logger;
3133

3234
/**
3335
* Helper trait for transactional operations
@@ -66,4 +68,39 @@ protected function atomic(callable $fn, IDBConnection $db) {
6668
throw $e;
6769
}
6870
}
71+
72+
/**
73+
* Wrapper around atomic() to retry after a retryable exception occurred
74+
*
75+
* Certain transactions might need to be retried. This is especially useful
76+
* in highly concurrent requests where a deadlocks is thrown by the database
77+
* without waiting for the lock to be freed (e.g. due to MySQL/MariaDB deadlock
78+
* detection)
79+
*
80+
* @template T
81+
* @param callable $fn
82+
* @psalm-param callable():T $fn
83+
* @param IDBConnection $db
84+
* @param int $maxRetires
85+
*
86+
* @return mixed the result of the passed callable
87+
* @psalm-return T
88+
*
89+
* @throws Exception for possible errors of commit or rollback or the custom operations within the closure
90+
* @throws Throwable any other error caused by the closure
91+
*
92+
* @since 24.0.0
93+
*/
94+
protected function atomicRetry(callable $fn, IDBConnection $db, int $maxRetires = 3): mixed {
95+
for ($i = 0; $i < $maxRetires; $i++) {
96+
try {
97+
return $this->atomic($fn, $db);
98+
} catch (DbalException $e) {
99+
if (!$e->isRetryable() || $i === ($maxRetires - 1)) {
100+
throw $e;
101+
}
102+
logger('core')->warning('Retrying operation after retryable exception.', [ 'exception' => $e ]);
103+
}
104+
}
105+
}
69106
}

0 commit comments

Comments
 (0)