From e10e3496f4ee923de846f1905cc58799d68c593a Mon Sep 17 00:00:00 2001 From: Allison Guilhem Date: Wed, 17 Apr 2024 17:30:02 +1000 Subject: [PATCH] take into account call to db --- DependencyInjection/Configuration.php | 3 +- DependencyInjection/DoctrineExtension.php | 47 ++++++++++--------- Middleware/IdleConnectionMiddleware.php | 36 ++++++++++++++ Resources/config/dbal.xml | 4 +- Resources/config/middlewares.xml | 5 ++ .../IdleConnectionMiddlewareTest.php | 25 ++++++++++ 6 files changed, 94 insertions(+), 26 deletions(-) create mode 100644 Middleware/IdleConnectionMiddleware.php create mode 100644 Tests/Middleware/IdleConnectionMiddlewareTest.php diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 68e40fc1..ddacf561 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -221,10 +221,9 @@ private function getDbalConnectionsNode(): ArrayNodeDefinition ->end() ->booleanNode('disable_type_comments')->end() ->scalarNode('server_version')->end() - ->integerNode('check_connection_timing')->end() + ->integerNode('idle_connection_ttl')->defaultValue(600)->end() ->scalarNode('driver_class')->end() ->scalarNode('wrapper_class')->end() - ->scalarNode('check_connection_frequency')->defaultValue(30)->end() ->booleanNode('keep_slave') ->setDeprecated( 'doctrine/doctrine-bundle', diff --git a/DependencyInjection/DoctrineExtension.php b/DependencyInjection/DoctrineExtension.php index f08570e8..d126412a 100644 --- a/DependencyInjection/DoctrineExtension.php +++ b/DependencyInjection/DoctrineExtension.php @@ -12,6 +12,7 @@ use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\IdGeneratorPass; use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\ServiceRepositoryCompilerPass; use Doctrine\Bundle\DoctrineBundle\EventSubscriber\EventSubscriberInterface; +use Doctrine\Bundle\DoctrineBundle\Middleware\IdleConnectionMiddleware; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryInterface; use Doctrine\Common\Annotations\Annotation; use Doctrine\DBAL\Connection; @@ -37,6 +38,7 @@ use Symfony\Bridge\Doctrine\DependencyInjection\AbstractDoctrineExtension; use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator; use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator; +use Symfony\Bridge\Doctrine\Middleware\IdleConnection\Listener; use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor; use Symfony\Bridge\Doctrine\SchemaListener\DoctrineDbalCacheAdapterSchemaListener; use Symfony\Bridge\Doctrine\SchemaListener\LockStoreSchemaListener; @@ -83,7 +85,7 @@ * * @final since 2.9 * @psalm-type DBALConfig = array{ - * connections: array, + * connections: array, * driver_schemes: array, * default_connection: string, * types: array, @@ -174,12 +176,6 @@ protected function dbalLoad(array $config, ContainerBuilder $container) $config['default_connection'] = reset($keys); } - if (! $container->hasParameter('kernel.runtime_mode') && ! $container->hasParameter('kernel.runtime_mode.worker')) { - $container->removeDefinition('doctrine.listeners.doctrine_connection_listener'); - } else { - $container->getDefinition('doctrine.orm.listeners.doctrine_connection_listener')->setArgument(1, $config['check_connection_timing']); - } - $this->defaultConnection = $config['default_connection']; $container->setAlias('database_connection', sprintf('doctrine.dbal.%s_connection', $this->defaultConnection)); @@ -202,13 +198,8 @@ protected function dbalLoad(array $config, ContainerBuilder $container) $connWithLogging = []; $connWithProfiling = []; $connWithBacktrace = []; - $timingByConnection = []; - $skipTiming = false; - - if (! $container->hasParameter('kernel.runtime_mode') && ! $container->hasParameter('kernel.runtime_mode.worker')) { - $container->removeDefinition('doctrine.listeners.doctrine_connection_listener'); - $skipTiming = true; - } + $ttlByConnection = []; + $connWithTtl = []; foreach ($config['connections'] as $name => $connection) { if ($connection['logging']) { @@ -223,17 +214,14 @@ protected function dbalLoad(array $config, ContainerBuilder $container) } } - if (! $skipTiming) { - $timingByConnection[] = ['name' => $connections[$name], 'timing' => $connection['check_connection_timing']]; + if ($connection['idle_connection_ttl']) { + $connWithTtl[] = $name; + $ttlByConnection[$name] = $connection['idle_connection_ttl']; } $this->loadDbalConnection($name, $connection, $container); } - if (! $skipTiming) { - $container->getDefinition('doctrine.orm.listeners.doctrine_connection_listener')->setArgument(1, $timingByConnection); - } - $container->registerForAutoconfiguration(MiddlewareInterface::class)->addTag('doctrine.middleware'); $container->registerAttributeForAutoconfiguration(AsMiddleware::class, static function (ChildDefinition $definition, AsMiddleware $attribute) { @@ -250,7 +238,14 @@ protected function dbalLoad(array $config, ContainerBuilder $container) } }); - $this->registerDbalMiddlewares($container, $connWithLogging, $connWithProfiling, $connWithBacktrace); + $this->registerDbalMiddlewares($container, $connWithLogging, $connWithProfiling, $connWithBacktrace, $connWithTtl); + + $container->getDefinition('doctrine.dbal.idle_connection_middleware')->setArgument(1, $ttlByConnection); + + if (! class_exists(Listener::class)) { + $container->removeDefinition('doctrine.dbal.idle_connection_listener'); + $container->removeDefinition('doctrine.dbal.idle_connection_middleware'); + } } /** @@ -1196,12 +1191,14 @@ private function createArrayAdapterCachePool(ContainerBuilder $container, string * @param string[] $connWithLogging * @param string[] $connWithProfiling * @param string[] $connWithBacktrace + * @param string[] $connWithTtl */ private function registerDbalMiddlewares( ContainerBuilder $container, array $connWithLogging, array $connWithProfiling, - array $connWithBacktrace + array $connWithBacktrace, + array $connWithTtl ): void { $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('middlewares.xml'); @@ -1217,5 +1214,11 @@ private function registerDbalMiddlewares( $debugMiddlewareAbstractDef ->addTag('doctrine.middleware', ['connection' => $connName]); } + + $idleConnectionMiddlewareAbstractDef = $container->getDefinition('doctrine.dbal.idle_connection_middleware'); + foreach ($connWithTtl as $connName) { + $idleConnectionMiddlewareAbstractDef + ->addTag('doctrine.middleware', ['connection' => $connName, 'priority' => 10]); + } } } diff --git a/Middleware/IdleConnectionMiddleware.php b/Middleware/IdleConnectionMiddleware.php new file mode 100644 index 00000000..2c9d29b8 --- /dev/null +++ b/Middleware/IdleConnectionMiddleware.php @@ -0,0 +1,36 @@ + */ + private array $ttlByConnection; + private string $connectionName; + + /** + * @param ArrayObject $connectionExpiries + * @param array $ttlByConnection + */ + public function __construct(ArrayObject $connectionExpiries, array $ttlByConnection) + { + $this->connectionExpiries = $connectionExpiries; + $this->ttlByConnection = $ttlByConnection; + } + + public function setConnectionName(string $name): void + { + $this->connectionName = $name; + } + + public function wrap(Driver $driver): Driver + { + return new IdleConnectionDriver($driver, $this->connectionExpiries, $this->ttlByConnection[$this->connectionName], $this->connectionName); + } +} diff --git a/Resources/config/dbal.xml b/Resources/config/dbal.xml index 3057d3b3..61fcb5ed 100644 --- a/Resources/config/dbal.xml +++ b/Resources/config/dbal.xml @@ -101,9 +101,9 @@ - + + - diff --git a/Resources/config/middlewares.xml b/Resources/config/middlewares.xml index d6bf92bc..28c3c330 100644 --- a/Resources/config/middlewares.xml +++ b/Resources/config/middlewares.xml @@ -5,6 +5,7 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + @@ -17,5 +18,9 @@ + + + + diff --git a/Tests/Middleware/IdleConnectionMiddlewareTest.php b/Tests/Middleware/IdleConnectionMiddlewareTest.php new file mode 100644 index 00000000..4baf33ac --- /dev/null +++ b/Tests/Middleware/IdleConnectionMiddlewareTest.php @@ -0,0 +1,25 @@ + time() - 30, 'connectiontwo' => time() + 40]); + $ttlByConnection = ['connectionone' => 25, 'connectiontwo' => 60]; + + $middleware = new IdleConnectionMiddleware($connectionExpiries, $ttlByConnection); + $middleware->setConnectionName('connectionone'); + + $driverMock = $this->createMock(Driver::class); + $wrappedDriver = $middleware->wrap($driverMock); + + $this->assertInstanceOf(IdleConnectionDriver::class, $wrappedDriver); + } +}