From 3cb1e659f906790390a9aa964c29b51af21e7114 Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 18 Aug 2025 17:18:29 +0300 Subject: [PATCH 1/6] sleep --- src/Database/Adapter.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index c4579715f..b8ddbc2c3 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -380,9 +380,14 @@ public function withTransaction(callable $callback): mixed } catch (\Throwable $action) { try { $this->rollbackTransaction(); + + if($action->getMessage()==='Failed to start transaction'){ + var_dump($action); + } + // $this->inTransaction = 0; Should we set if rollback is success? } catch (\Throwable $rollback) { if ($attempts < 2) { - \usleep(5000); // 5ms + \usleep(5000 * ($attempts + 1)); continue; } @@ -391,7 +396,7 @@ public function withTransaction(callable $callback): mixed } if ($attempts < 2) { - \usleep(5000); // 5ms + \usleep(5000 * ($attempts + 1)); continue; } From 82ca60b4b0ed3d67f12f4aa322d4f68fa674332d Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 18 Aug 2025 18:41:00 +0300 Subject: [PATCH 2/6] Fix logic --- src/Database/Adapter.php | 7 +++---- src/Database/Adapter/SQL.php | 22 ++++++++-------------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index b8ddbc2c3..8d524d23b 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -379,12 +379,11 @@ public function withTransaction(callable $callback): mixed return $result; } catch (\Throwable $action) { try { + var_dump($action->getMessage()); + $this->rollbackTransaction(); - if($action->getMessage()==='Failed to start transaction'){ - var_dump($action); - } - // $this->inTransaction = 0; Should we set if rollback is success? + //$this->inTransaction = 0;// Should we set if rollback is success? } catch (\Throwable $rollback) { if ($attempts < 2) { \usleep(5000 * ($attempts + 1)); diff --git a/src/Database/Adapter/SQL.php b/src/Database/Adapter/SQL.php index 7b45fc102..81c2fbf72 100644 --- a/src/Database/Adapter/SQL.php +++ b/src/Database/Adapter/SQL.php @@ -43,20 +43,18 @@ public function startTransaction(): bool $this->getPDO()->prepare('ROLLBACK')->execute(); } - $result = $this->getPDO()->beginTransaction(); + $this->getPDO()->beginTransaction(); + } else { - $result = $this->getPDO()->exec('SAVEPOINT transaction' . $this->inTransaction); + $this->getPDO()->exec('SAVEPOINT transaction' . $this->inTransaction); // returns 0 } } catch (PDOException $e) { throw new TransactionException('Failed to start transaction: ' . $e->getMessage(), $e->getCode(), $e); } - if (!$result) { - throw new TransactionException('Failed to start transaction'); - } - $this->inTransaction++; - return $result; + + return true; } /** @@ -101,21 +99,17 @@ public function rollbackTransaction(): bool try { if ($this->inTransaction > 1) { - $result = $this->getPDO()->exec('ROLLBACK TO transaction' . ($this->inTransaction - 1)); + $this->getPDO()->exec('ROLLBACK TO transaction' . ($this->inTransaction - 1)); $this->inTransaction--; } else { - $result = $this->getPDO()->rollBack(); + $this->getPDO()->rollBack(); $this->inTransaction = 0; } } catch (PDOException $e) { throw new DatabaseException('Failed to rollback transaction: ' . $e->getMessage(), $e->getCode(), $e); } - if (!$result) { - throw new TransactionException('Failed to rollback transaction'); - } - - return $result; + return true; } /** From 502fec05bd1f27d7ee63cb2f5a9f9bc5875dd350 Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 18 Aug 2025 18:41:49 +0300 Subject: [PATCH 3/6] Remove comment --- src/Database/Adapter/SQL.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Adapter/SQL.php b/src/Database/Adapter/SQL.php index 81c2fbf72..a0e7b5fd7 100644 --- a/src/Database/Adapter/SQL.php +++ b/src/Database/Adapter/SQL.php @@ -46,7 +46,7 @@ public function startTransaction(): bool $this->getPDO()->beginTransaction(); } else { - $this->getPDO()->exec('SAVEPOINT transaction' . $this->inTransaction); // returns 0 + $this->getPDO()->exec('SAVEPOINT transaction' . $this->inTransaction); } } catch (PDOException $e) { throw new TransactionException('Failed to start transaction: ' . $e->getMessage(), $e->getCode(), $e); From 1c3e1cfa921d2a474b5058f2420f9698bb700b85 Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 19 Aug 2025 08:50:06 +0300 Subject: [PATCH 4/6] Address comments --- src/Database/Adapter.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index 8d524d23b..f25d60582 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -371,6 +371,8 @@ public function inTransaction(): bool */ public function withTransaction(callable $callback): mixed { + $sleep = 100_000; // 100 milliseconds + for ($attempts = 0; $attempts < 3; $attempts++) { try { $this->startTransaction(); @@ -379,14 +381,10 @@ public function withTransaction(callable $callback): mixed return $result; } catch (\Throwable $action) { try { - var_dump($action->getMessage()); - $this->rollbackTransaction(); - - //$this->inTransaction = 0;// Should we set if rollback is success? } catch (\Throwable $rollback) { if ($attempts < 2) { - \usleep(5000 * ($attempts + 1)); + \usleep($sleep * ($attempts + 1)); continue; } @@ -395,7 +393,7 @@ public function withTransaction(callable $callback): mixed } if ($attempts < 2) { - \usleep(5000 * ($attempts + 1)); + \usleep($sleep * ($attempts + 1)); continue; } From c95a5d676f94ebf1e2eaf4f9efa7e8475f6e7556 Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 19 Aug 2025 10:47:52 +0300 Subject: [PATCH 5/6] Skip specific exceptions --- src/Database/Adapter.php | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index f25d60582..87ba25ab7 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -4,7 +4,12 @@ use Exception; use Utopia\Database\Exception as DatabaseException; +use Utopia\Database\Exception\Authorization as AuthorizationException; +use Utopia\Database\Exception\Conflict as ConflictException; use Utopia\Database\Exception\Duplicate as DuplicateException; +use Utopia\Database\Exception\Limit as LimitException; +use Utopia\Database\Exception\Relationship as RelationshipException; +use Utopia\Database\Exception\Restricted as RestrictedException; use Utopia\Database\Exception\Timeout as TimeoutException; use Utopia\Database\Exception\Transaction as TransactionException; @@ -372,8 +377,10 @@ public function inTransaction(): bool public function withTransaction(callable $callback): mixed { $sleep = 100_000; // 100 milliseconds + $retries = 2; + $retries = 0; - for ($attempts = 0; $attempts < 3; $attempts++) { + for ($attempts = 0; $attempts <= $retries; $attempts++) { try { $this->startTransaction(); $result = $callback(); @@ -382,8 +389,21 @@ public function withTransaction(callable $callback): mixed } catch (\Throwable $action) { try { $this->rollbackTransaction(); + + if ( + $action instanceof DuplicateException || + $action instanceof RestrictedException || + $action instanceof AuthorizationException || + $action instanceof RelationshipException || + $action instanceof ConflictException || + $action instanceof LimitException + ) { + $this->inTransaction = 0; + throw $action; + } + } catch (\Throwable $rollback) { - if ($attempts < 2) { + if ($attempts < $retries) { \usleep($sleep * ($attempts + 1)); continue; } @@ -392,7 +412,7 @@ public function withTransaction(callable $callback): mixed throw $rollback; } - if ($attempts < 2) { + if ($attempts < $retries) { \usleep($sleep * ($attempts + 1)); continue; } From 8ce83a1b8a1d4b2ace216e6fffc0a07dd4f94035 Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 19 Aug 2025 10:51:10 +0300 Subject: [PATCH 6/6] 2 retries --- src/Database/Adapter.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index 87ba25ab7..6f285feae 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -378,7 +378,6 @@ public function withTransaction(callable $callback): mixed { $sleep = 100_000; // 100 milliseconds $retries = 2; - $retries = 0; for ($attempts = 0; $attempts <= $retries; $attempts++) { try {