Skip to content

Commit fad4504

Browse files
committed
Add retryable connection
1 parent 10d3053 commit fad4504

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

src/RetryConnection.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
namespace ipl\Sql;
4+
5+
use Exception;
6+
use PDOStatement;
7+
8+
class RetryConnection extends Connection
9+
{
10+
/** @var int Number of retries to be performed before giving up */
11+
protected $retries;
12+
13+
/** @var string[] A list of PDO retryable errors */
14+
protected static $retryableErrors = [
15+
'server has gone away',
16+
'no connection to the server',
17+
'Lost connection',
18+
'Connection was killed',
19+
'Connection refused',
20+
'Error while sending',
21+
'is dead or not enabled',
22+
'decryption failed or bad record mac',
23+
'server closed the connection unexpectedly',
24+
'SSL connection has been closed unexpectedly',
25+
'Error writing data to the connection',
26+
'Resource deadlock avoided',
27+
'Transaction() on null',
28+
'child connection forced to terminate due to client_idle_limit',
29+
'query_wait_timeout',
30+
'reset by peer',
31+
'Physical connection is not usable',
32+
'TCP Provider: Error code 0x68',
33+
'ORA-03114',
34+
'Packets out of order. Expected',
35+
'Adaptive Server connection failed',
36+
'Communication link failure',
37+
'No such file or directory',
38+
];
39+
40+
public function __construct($config, int $numberRetries = 1)
41+
{
42+
parent::__construct($config);
43+
44+
$this->retries = $numberRetries;
45+
}
46+
47+
public function prepexec($stmt, $values = null)
48+
{
49+
$retries = 0;
50+
$retryHandler = function () use (&$retryHandler, &$retries, $stmt, $values): PDOStatement {
51+
try {
52+
return parent::prepexec($stmt, $values);
53+
} catch (Exception $err) {
54+
if ($retries < $this->retries && static::isRetryable($err)) {
55+
$retries++;
56+
57+
$this->disconnect();
58+
59+
return $retryHandler();
60+
}
61+
62+
throw $err;
63+
}
64+
};
65+
66+
return $retryHandler();
67+
}
68+
69+
/**
70+
* Get whether the given (PDO) exception can be fixed by reconnecting to the database.
71+
*
72+
* @param Exception $err
73+
*
74+
* @return bool
75+
*/
76+
public static function isRetryable(Exception $err): bool
77+
{
78+
$message = $err->getMessage();
79+
foreach (static::$retryableErrors as $error) {
80+
if (strpos($message, $error) !== false) {
81+
return true;
82+
}
83+
}
84+
85+
return false;
86+
}
87+
}

0 commit comments

Comments
 (0)