rabin 5 hari lalu
induk
melakukan
d7394864f0
1 mengubah file dengan 45 tambahan dan 21 penghapusan
  1. 45 21
      src/Dever/Store/Pdo.php

+ 45 - 21
src/Dever/Store/Pdo.php

@@ -233,28 +233,41 @@ class Pdo extends Base
     }
     protected function withConnection($method, $sql, array $bind, callable $callback)
     {
-        $connection = null;
-        $broken = false;
-        try {
-            $connection = $this->borrowConnection($method);
-            $statement = $this->runStatement($connection, $sql, $bind);
-            if (Dever::get(Debug::class)->shell) {
-                $this->bsql($sql, $bind);
-                $this->log(array('sql' => $sql, 'count' => $statement->rowCount()));
-            }
-            return $callback($connection, $statement);
-        } catch (\RuntimeException $runtime) {
-            if (!$connection) {
-                Dever::out()->error($runtime->getMessage());
-            }
-            throw $runtime;
-        } catch (\PDOException $exception) {
-            $broken = true;
-            $this->error(array('sql' => $sql, 'msg' => $exception->getMessage()));
-        } finally {
-            if ($connection) {
-                $this->recycleConnection($method, $connection, $broken);
+        $attempts = 0;
+        while (true) {
+            $connection = null;
+            $broken = false;
+            try {
+                $connection = $this->borrowConnection($method);
+                $statement = $this->runStatement($connection, $sql, $bind);
+                if (Dever::get(Debug::class)->shell) {
+                    $this->bsql($sql, $bind);
+                    $this->log(array('sql' => $sql, 'count' => $statement->rowCount()));
+                }
+                return $callback($connection, $statement);
+            } catch (\RuntimeException $runtime) {
+                if (!$connection) {
+                    Dever::out()->error($runtime->getMessage());
+                }
+                throw $runtime;
+            } catch (\PDOException $exception) {
+                $broken = $this->isDisconnectException($exception);
+                if (!$broken || $attempts >= 1) {
+                    $this->error(array('sql' => $sql, 'msg' => $exception->getMessage()));
+                } else {
+                    $attempts++;
+                    if ($connection) {
+                        $this->recycleConnection($method, $connection, true);
+                        $connection = null;
+                    }
+                    continue;
+                }
+            } finally {
+                if ($connection) {
+                    $this->recycleConnection($method, $connection, $broken);
+                }
             }
+            break;
         }
     }
     protected function runStatement($connection, $sql, array $bind)
@@ -295,4 +308,15 @@ class Pdo extends Base
         }
         parent::releaseConnection($method, $connection, $broken);
     }
+    protected function isDisconnectException(\PDOException $exception): bool
+    {
+        $code = (int) $exception->getCode();
+        if (in_array($code, [2006, 2013, 2055], true)) {
+            return true;
+        }
+        $message = strtolower($exception->getMessage());
+        return str_contains($message, 'server has gone away') ||
+               str_contains($message, 'no connection to the server') ||
+               str_contains($message, 'lost connection');
+    }
 }