Skip to content

Instantly share code, notes, and snippets.

@grachevko
Last active November 21, 2017 14:59
Show Gist options
  • Save grachevko/8b87e9dfe3e0974987e2fdcfb71945ac to your computer and use it in GitHub Desktop.
Save grachevko/8b87e9dfe3e0974987e2fdcfb71945ac to your computer and use it in GitHub Desktop.
<?php
namespace AppBundle\Extensions\Doctrine\ORM;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\DBAL\Connections\MasterSlaveConnection;
use Doctrine\DBAL\DBALException;
class ReopeningConnectionWrapper extends MasterSlaveConnection
{
private const MYSQL_CONNECTION_TIMED_WAIT_CODE = 2006;
private const GONE_AWAY_MESSAGE = 'MySQL server has gone away';
private const ERROR_ON_SENDING_PACKET = 'Error while sending QUERY packet';
private const RETRIES = 5;
public function executeQuery($query, array $params = [], $types = [], QueryCacheProfile $qcp = null)
{
$this->connect('slave');
return $this->wrap(__METHOD__, func_get_args());
}
public function executeUpdate($query, array $params = [], array $types = [])
{
return $this->wrap(__METHOD__, func_get_args());
}
public function query()
{
return $this->wrap(__METHOD__, func_get_args());
}
public function exec($statement)
{
return $this->wrap(__METHOD__, func_get_args());
}
public function lastInsertId($seqName = null)
{
return $this->wrap(__METHOD__, func_get_args());
}
public function beginTransaction()
{
return $this->wrap(__METHOD__, func_get_args());
}
public function getWrappedConnection()
{
return $this->wrap(__METHOD__, func_get_args());
}
public function releaseSavepoint($savepoint)
{
return $this->wrap(__METHOD__, func_get_args());
}
public function createSavepoint($savepoint)
{
return $this->wrap(__METHOD__, func_get_args());
}
public function rollbackSavepoint($savepoint)
{
return $this->wrap(__METHOD__, func_get_args());
}
public function quote($input, $type = null)
{
return $this->wrap(__METHOD__, func_get_args());
}
private function wrap($method, $arguments)
{
for ($i = 0; $i < self::RETRIES; $i++) {
try {
return call_user_func_array('parent::'.$method, $arguments);
} catch (\ErrorException | DBALException | \PDOException $e) {
if ($this->canReconnect($e)) {
$this->close();
$this->connect();
} else {
throw $e;
}
}
}
}
private function canReconnect(\Exception $e): bool
{
return false !== stripos($e->getMessage(), self::GONE_AWAY_MESSAGE)
|| false !== stripos($e->getMessage(), self::ERROR_ON_SENDING_PACKET);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment