mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-23 18:03:17 +00:00
Merge pull request #1006 from romainneutron/fix-connection-master
[Ready][3.9] Add reconnectable connection
This commit is contained in:
@@ -14,6 +14,7 @@ namespace Alchemy\Phrasea;
|
||||
use Alchemy\Phrasea\Command\CommandInterface;
|
||||
use Alchemy\Phrasea\Core\CLIProvider\TranslationExtractorServiceProvider;
|
||||
use Alchemy\Phrasea\Core\CLIProvider\WebsocketServerServiceProvider;
|
||||
use Alchemy\Phrasea\Core\PhraseaCLIExceptionHandler;
|
||||
use Alchemy\Phrasea\Exception\RuntimeException;
|
||||
use Symfony\Component\Console;
|
||||
use Alchemy\Phrasea\Core\CLIProvider\CLIDriversServiceProvider;
|
||||
@@ -23,6 +24,7 @@ use Alchemy\Phrasea\Core\CLIProvider\LessBuilderServiceProvider;
|
||||
use Alchemy\Phrasea\Core\CLIProvider\PluginServiceProvider;
|
||||
use Alchemy\Phrasea\Core\CLIProvider\SignalHandlerServiceProvider;
|
||||
use Alchemy\Phrasea\Core\CLIProvider\TaskManagerServiceProvider;
|
||||
use Symfony\Component\Debug\ErrorHandler;
|
||||
|
||||
/**
|
||||
* Phraseanet Command Line Application
|
||||
@@ -66,6 +68,10 @@ class CLI extends Application
|
||||
$this->register(new DoctrineMigrationServiceProvider());
|
||||
|
||||
$this->bindRoutes();
|
||||
|
||||
error_reporting(-1);
|
||||
ErrorHandler::register();
|
||||
PhraseaCLIExceptionHandler::register();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
|
@@ -955,12 +955,15 @@ class Collection implements ControllerProviderInterface
|
||||
$success = false;
|
||||
|
||||
$collection = \collection::get_from_base_id($app, $bas_id);
|
||||
$prefs = $request->request->get('str');
|
||||
|
||||
try {
|
||||
$domdoc = new \DOMDocument();
|
||||
if ($domdoc->loadXML($request->request->get('str'))) {
|
||||
$collection->set_prefs($domdoc);
|
||||
$success = true;
|
||||
if ('' !== trim($prefs)) {
|
||||
$domdoc = new \DOMDocument();
|
||||
if (true === $domdoc->loadXML($prefs)) {
|
||||
$collection->set_prefs($domdoc);
|
||||
$success = true;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -13,8 +13,9 @@ 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;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class ConnectionProvider
|
||||
{
|
||||
@@ -24,9 +25,11 @@ class ConnectionProvider
|
||||
*/
|
||||
private $connections = [];
|
||||
private $eventManager;
|
||||
private $logger;
|
||||
|
||||
public function __construct(Configuration $config, EventManager $eventManager)
|
||||
public function __construct(Configuration $config, EventManager $eventManager, LoggerInterface $logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->config = $config;
|
||||
$this->eventManager = $eventManager;
|
||||
}
|
||||
@@ -58,6 +61,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), $this->logger);
|
||||
}
|
||||
}
|
||||
|
151
lib/Alchemy/Phrasea/Core/Connection/ReconnectableConnection.php
Normal file
151
lib/Alchemy/Phrasea/Core/Connection/ReconnectableConnection.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?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;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class ReconnectableConnection implements ConnectionInterface
|
||||
{
|
||||
const MYSQL_CONNECTION_TIMED_WAIT_CODE = 2006;
|
||||
|
||||
/** @var Connection */
|
||||
private $connection;
|
||||
private $logger;
|
||||
|
||||
public function __construct(ConnectionInterface $connection, LoggerInterface $logger)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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 {
|
||||
return call_user_func_array([$this->connection, $method], $args);
|
||||
} catch (\Exception $exception) {
|
||||
$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();
|
||||
$this->logger->notice('Connection to MySQL lost, reconnect okay.');
|
||||
|
||||
return call_user_func_array([$this->connection, $method], $args);
|
||||
}
|
||||
if (
|
||||
(false !== strpos($exception->getMessage(), 'MySQL server has gone away'))
|
||||
|| (false !== strpos($exception->getMessage(), 'Error while sending QUERY packet'))
|
||||
|| (false !== strpos($exception->getMessage(), 'errno=32 Broken pipe'))
|
||||
) {
|
||||
$this->connection->close();
|
||||
$this->connection->connect();
|
||||
$this->logger->notice('Connection to MySQL lost, reconnect okay.');
|
||||
|
||||
return call_user_func_array([$this->connection, $method], $args);
|
||||
}
|
||||
$this->logger->critical('Connection to MySQL lost, unable to reconnect.', ['exception' => $exception]);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
22
lib/Alchemy/Phrasea/Core/PhraseaCLIExceptionHandler.php
Normal file
22
lib/Alchemy/Phrasea/Core/PhraseaCLIExceptionHandler.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\Debug\ExceptionHandler as SymfonyExceptionHandler;
|
||||
|
||||
class PhraseaCLIExceptionHandler extends SymfonyExceptionHandler
|
||||
{
|
||||
public function handle(\Exception $exception)
|
||||
{
|
||||
throw $exception;
|
||||
}
|
||||
}
|
@@ -150,7 +150,7 @@ class ORMServiceProvider implements ServiceProviderInterface
|
||||
});
|
||||
|
||||
$app['dbal.provider'] = $app->share(function (Application $app) {
|
||||
return new ConnectionProvider($app['EM.config'], $app['EM.events-manager']);
|
||||
return new ConnectionProvider($app['EM.config'], $app['EM.events-manager'], isset($app['task-manager.logger']) ? $app['task-manager.logger'] : $app['monolog']);
|
||||
});
|
||||
|
||||
$app['EM'] = $app->share(function (Application $app) {
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Driver\Connection;
|
||||
|
||||
interface patchthesaurus_interface
|
||||
{
|
||||
|
@@ -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);
|
||||
|
@@ -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'], $this->createLoggerMock());
|
||||
$conn = $provider->get(self::$DI['app']['conf']->get(['main', 'database']));
|
||||
$conn->exec('SET @@local.wait_timeout= 1');
|
||||
usleep(1200000);
|
||||
$conn->exec('SHOW DATABASES');
|
||||
}
|
||||
}
|
@@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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()
|
||||
|
@@ -14,6 +14,8 @@ use Symfony\Component\Debug\ErrorHandler;
|
||||
|
||||
require_once __DIR__ . "/../lib/autoload.php";
|
||||
|
||||
error_reporting(-1);
|
||||
|
||||
ErrorHandler::register();
|
||||
|
||||
$environment = Application::ENV_DEV;
|
||||
|
Reference in New Issue
Block a user