Skip to content

Commit

Permalink
Add retryable connection
Browse files Browse the repository at this point in the history
  • Loading branch information
yhabteab committed Jul 17, 2023
1 parent 10d3053 commit be4e327
Showing 1 changed file with 87 additions and 0 deletions.
87 changes: 87 additions & 0 deletions src/RetryConnection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

namespace ipl\Sql;

use Exception;
use PDOStatement;

class RetryConnection extends Connection
{
/** @var int Number of retries to be performed before giving up */
protected $retries;

/** @var string[] A list of PDO retryable errors */
protected static $retryableErrors = [
'server has gone away',
'no connection to the server',
'Lost connection',
'Connection was killed',
'Connection refused',
'Error while sending',
'is dead or not enabled',
'decryption failed or bad record mac',
'server closed the connection unexpectedly',
'SSL connection has been closed unexpectedly',
'Error writing data to the connection',
'Resource deadlock avoided',
'Transaction() on null',
'child connection forced to terminate due to client_idle_limit',
'query_wait_timeout',
'reset by peer',
'Physical connection is not usable',
'TCP Provider: Error code 0x68',
'ORA-03114',
'Packets out of order. Expected',
'Adaptive Server connection failed',
'Communication link failure',
'No such file or directory',
];

public function __construct($config, int $numberRetries = 1)
{
parent::__construct($config);

$this->retries = $numberRetries;
}

public function prepexec($stmt, $values = null)
{
$retries = 0;
$retryHandler = function () use (&$retryHandler, &$retries, $stmt, $values): PDOStatement {
try {
return parent::prepexec($stmt, $values);
} catch (Exception $err) {
if ($retries < $this->retries && $this->isRetryable($err)) {
$retries++;

$this->disconnect();

return $retryHandler();
}

throw $err;
}
};

return $retryHandler();
}

/**
* Get whether the given (PDO) exception can be fixed by reconnecting to the database.
*
* @param Exception $err
*
* @return bool
*/
public static function isRetryable(Exception $err): bool
{
$message = $err->getMessage();
foreach (static::$retryableErrors as $error) {
if (strpos($message, $error) !== false) {
return true;
}
}

return false;
}
}

0 comments on commit be4e327

Please sign in to comment.