Add reconnectable connection

This commit is contained in:
Romain Neutron
2014-03-03 00:57:25 +01:00
parent 31de811cf5
commit 8cf73891c0
21 changed files with 184 additions and 21 deletions

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\Command\Setup;
use Alchemy\Phrasea\Command\Command;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

View File

@@ -11,7 +11,7 @@
namespace Alchemy\Phrasea\Controller\Thesaurus;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
use Silex\Application;
use Silex\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Request;

View File

@@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\Core\Connection;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\DriverManager;
class ConnectionProvider
@@ -58,6 +58,6 @@ class ConnectionProvider
return $this->connections[$key];
}
return $this->connections[$key] = DriverManager::getConnection($params, $this->config, $this->eventManager);;
return $this->connections[$key] = new ReconnectableConnection(DriverManager::getConnection($params, $this->config, $this->eventManager));
}
}

View File

@@ -0,0 +1,146 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Connection;
use Doctrine\DBAL\Driver\Connection as ConnectionInterface;
class ReconnectableConnection implements ConnectionInterface
{
const MYSQL_CONNECTION_TIMED_WAIT_CODE = 2006;
/** @var Connection */
private $connection;
public function __construct(ConnectionInterface $connection)
{
$this->connection = $connection;
}
/**
* {@inheritdoc}
*/
function prepare($prepareString)
{
return $this->tryMethod(__FUNCTION__, func_get_args());
}
/**
* {@inheritdoc}
*/
function query()
{
return $this->tryMethod(__FUNCTION__, func_get_args());
}
/**
* {@inheritdoc}
*/
function quote($input, $type=\PDO::PARAM_STR)
{
return $this->tryMethod(__FUNCTION__, func_get_args());
}
/**
* {@inheritdoc}
*/
function exec($statement)
{
return $this->tryMethod(__FUNCTION__, func_get_args());
}
/**
* {@inheritdoc}
*/
function lastInsertId($name = null)
{
return $this->tryMethod(__FUNCTION__, func_get_args());
}
/**
* {@inheritdoc}
*/
function beginTransaction()
{
return $this->tryMethod(__FUNCTION__, func_get_args());
}
/**
* {@inheritdoc}
*/
function commit()
{
return $this->tryMethod(__FUNCTION__, func_get_args());
}
/**
* {@inheritdoc}
*/
function rollBack()
{
return $this->tryMethod(__FUNCTION__, func_get_args());
}
/**
* {@inheritdoc}
*/
function errorCode()
{
return $this->tryMethod(__FUNCTION__, func_get_args());
}
/**
* {@inheritdoc}
*/
function errorInfo()
{
return $this->tryMethod(__FUNCTION__, func_get_args());
}
/**
* {@inheritdoc}
*/
public function __call($method, $args)
{
return $this->tryMethod($method, $args);
}
private function tryMethod($method, $args)
{
try {
set_error_handler(function ($errno, $errstr) { throw new \Exception($errstr, $errno); });
$ret = call_user_func_array([$this->connection, $method], $args);
restore_error_handler();
return $ret;
} catch (\Exception $exception) {
restore_error_handler();
$e = $exception;
while ($e->getPrevious() && !$e instanceof \PDOException) {
$e = $e->getPrevious();
}
if ($e instanceof \PDOException && $e->errorInfo[1] == self::MYSQL_CONNECTION_TIMED_WAIT_CODE) {
$this->connection->close();
$this->connection->connect();
return call_user_func_array([$this->connection, $method], $args);
}
if ((false !== strpos($exception->getMessage(), 'MySQL server has gone away')) || (false !== strpos($exception->getMessage(), 'errno=32 Broken pipe'))) {
$this->connection->close();
$this->connection->connect();
return call_user_func_array([$this->connection, $method], $args);
}
throw $e;
}
}
}

View File

@@ -14,7 +14,7 @@ namespace Alchemy\Phrasea\Model\Manager;
use Doctrine\Common\Persistence\ObjectManager;
use Alchemy\Phrasea\Model\Entities\User;
use Alchemy\Phrasea\Model\Entities\UserSetting;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\ORM\UnitOfWork AS UOW;
class UserManager

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\Setup;
use Alchemy\Phrasea\Application;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\ORM\Tools\SchemaTool;
use Alchemy\Phrasea\Model\Entities\User;

View File

@@ -13,7 +13,7 @@ use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Core\Version as PhraseaVersion;
use vierbergenlars\SemVer\version;
use Alchemy\Phrasea\Model\Entities\User;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
abstract class base implements cache_cacheableInterface
{

View File

@@ -12,7 +12,7 @@
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Exception\InvalidArgumentException;
use Alchemy\Phrasea\Model\Entities\User;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
class collection implements cache_cacheableInterface
{

View File

@@ -12,7 +12,7 @@
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Model\Entities\User;
use Alchemy\Phrasea\Exception\InvalidArgumentException;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Translation\TranslatorInterface;

View File

@@ -13,7 +13,7 @@ use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Vocabulary;
use Alchemy\Phrasea\Vocabulary\ControlProvider\ControlProviderInterface;
use Alchemy\Phrasea\Metadata\Tag\Nosource;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
use PHPExiftool\Driver\TagInterface;
use PHPExiftool\Driver\TagFactory;
use PHPExiftool\Exception\TagUnknown;

View File

@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
class patchthesaurus_100 implements patchthesaurus_interface
{

View File

@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
class patchthesaurus_200 implements patchthesaurus_interface
{

View File

@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
class patchthesaurus_201 implements patchthesaurus_interface
{

View File

@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
class patchthesaurus_202 implements patchthesaurus_interface
{

View File

@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
class patchthesaurus_203 implements patchthesaurus_interface
{

View File

@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
class patchthesaurus_204 implements patchthesaurus_interface
{

View File

@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection;
interface patchthesaurus_interface
{

View File

@@ -84,7 +84,7 @@ class InstallTest extends \PhraseanetTestCase
self::$DI['cli']['phraseanet.installer']->expects($this->once())
->method('install')
->with($email, $password, $this->isInstanceOf('Doctrine\DBAL\Connection'), $serverName, $dataPath, $this->isInstanceOf('Doctrine\DBAL\Connection'), $template, $this->anything());
->with($email, $password, $this->isInstanceOf('Doctrine\DBAL\Driver\Connection'), $serverName, $dataPath, $this->isInstanceOf('Doctrine\DBAL\Driver\Connection'), $template, $this->anything());
$command = new Install('system:check');
$command->setHelperSet($helperSet);

View File

@@ -0,0 +1,17 @@
<?php
namespace Alchemy\Tests\Phrasea\Core\Connection;
use Alchemy\Phrasea\Core\Connection\ConnectionProvider;
class ConnectionProviderTest extends \PhraseanetTestCase
{
public function testMysqlTimeoutIsHandled()
{
$provider = new ConnectionProvider(self::$DI['app']['EM.config'], self::$DI['app']['EM.events-manager']);
$conn = $provider->get(self::$DI['app']['conf']->get(['main', 'database']));
$conn->exec('SET @@local.wait_timeout= 1');
usleep(1200000);
$conn->exec('SHOW DATABASES');
}
}

View File

@@ -112,7 +112,7 @@ class collectionTest extends \PhraseanetAuthenticatedTestCase
public function testGet_connection()
{
$this->assertInstanceOf('Doctrine\DBAL\Connection', self::$object->get_connection());
$this->assertInstanceOf('Doctrine\DBAL\Driver\Connection', self::$object->get_connection());
}
/**

View File

@@ -70,8 +70,8 @@ class databox_fieldTest extends \PhraseanetTestCase
public function testGet_connection()
{
$this->assertInstanceOf('Doctrine\DBAL\Connection', $this->object_mono->get_connection());
$this->assertInstanceOf('Doctrine\DBAL\Connection', $this->object_multi->get_connection());
$this->assertInstanceOf('Doctrine\DBAL\Driver\Connection', $this->object_mono->get_connection());
$this->assertInstanceOf('Doctrine\DBAL\Driver\Connection', $this->object_multi->get_connection());
}
public function testGet_databox()