Skip to content

Commit 35ac4e9

Browse files
committed
take into account call to db
1 parent eadaa66 commit 35ac4e9

File tree

8 files changed

+152
-26
lines changed

8 files changed

+152
-26
lines changed

DependencyInjection/Configuration.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -221,10 +221,9 @@ private function getDbalConnectionsNode(): ArrayNodeDefinition
221221
->end()
222222
->booleanNode('disable_type_comments')->end()
223223
->scalarNode('server_version')->end()
224-
->integerNode('check_connection_timing')->end()
224+
->integerNode('idle_connection_ttl')->defaultValue(600)->end()
225225
->scalarNode('driver_class')->end()
226226
->scalarNode('wrapper_class')->end()
227-
->scalarNode('check_connection_frequency')->defaultValue(30)->end()
228227
->booleanNode('keep_slave')
229228
->setDeprecated(
230229
'doctrine/doctrine-bundle',

DependencyInjection/DoctrineExtension.php

+26-22
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
use Symfony\Bridge\Doctrine\DependencyInjection\AbstractDoctrineExtension;
3838
use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator;
3939
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
40+
use Symfony\Bridge\Doctrine\Middleware\IdleConnection\Listener;
4041
use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor;
4142
use Symfony\Bridge\Doctrine\SchemaListener\DoctrineDbalCacheAdapterSchemaListener;
4243
use Symfony\Bridge\Doctrine\SchemaListener\LockStoreSchemaListener;
@@ -83,7 +84,7 @@
8384
*
8485
* @final since 2.9
8586
* @psalm-type DBALConfig = array{
86-
* connections: array<string, array{logging: bool, profiling: bool, profiling_collect_backtrace: bool}>,
87+
* connections: array<string, array{logging: bool, profiling: bool, profiling_collect_backtrace: bool, idle_connection_ttl: int}>,
8788
* driver_schemes: array<string, string>,
8889
* default_connection: string,
8990
* types: array<string, string>,
@@ -174,12 +175,6 @@ protected function dbalLoad(array $config, ContainerBuilder $container)
174175
$config['default_connection'] = reset($keys);
175176
}
176177

177-
if (! $container->hasParameter('kernel.runtime_mode') && ! $container->hasParameter('kernel.runtime_mode.worker')) {
178-
$container->removeDefinition('doctrine.listeners.doctrine_connection_listener');
179-
} else {
180-
$container->getDefinition('doctrine.orm.listeners.doctrine_connection_listener')->setArgument(1, $config['check_connection_timing']);
181-
}
182-
183178
$this->defaultConnection = $config['default_connection'];
184179

185180
$container->setAlias('database_connection', sprintf('doctrine.dbal.%s_connection', $this->defaultConnection));
@@ -202,13 +197,8 @@ protected function dbalLoad(array $config, ContainerBuilder $container)
202197
$connWithLogging = [];
203198
$connWithProfiling = [];
204199
$connWithBacktrace = [];
205-
$timingByConnection = [];
206-
$skipTiming = false;
207-
208-
if (! $container->hasParameter('kernel.runtime_mode') && ! $container->hasParameter('kernel.runtime_mode.worker')) {
209-
$container->removeDefinition('doctrine.listeners.doctrine_connection_listener');
210-
$skipTiming = true;
211-
}
200+
$ttlByConnection = [];
201+
$connWithTtl = [];
212202

213203
foreach ($config['connections'] as $name => $connection) {
214204
if ($connection['logging']) {
@@ -223,17 +213,14 @@ protected function dbalLoad(array $config, ContainerBuilder $container)
223213
}
224214
}
225215

226-
if (! $skipTiming) {
227-
$timingByConnection[] = ['name' => $connections[$name], 'timing' => $connection['check_connection_timing']];
216+
if ($connection['idle_connection_ttl'] > 0) {
217+
$connWithTtl[] = $name;
218+
$ttlByConnection[$name] = $connection['idle_connection_ttl'];
228219
}
229220

230221
$this->loadDbalConnection($name, $connection, $container);
231222
}
232223

233-
if (! $skipTiming) {
234-
$container->getDefinition('doctrine.orm.listeners.doctrine_connection_listener')->setArgument(1, $timingByConnection);
235-
}
236-
237224
$container->registerForAutoconfiguration(MiddlewareInterface::class)->addTag('doctrine.middleware');
238225

239226
$container->registerAttributeForAutoconfiguration(AsMiddleware::class, static function (ChildDefinition $definition, AsMiddleware $attribute) {
@@ -250,7 +237,16 @@ protected function dbalLoad(array $config, ContainerBuilder $container)
250237
}
251238
});
252239

253-
$this->registerDbalMiddlewares($container, $connWithLogging, $connWithProfiling, $connWithBacktrace);
240+
$this->registerDbalMiddlewares($container, $connWithLogging, $connWithProfiling, $connWithBacktrace, $connWithTtl);
241+
242+
$container->getDefinition('doctrine.dbal.idle_connection_middleware')->setArgument(1, $ttlByConnection);
243+
244+
if (class_exists(Listener::class)) {
245+
return;
246+
}
247+
248+
$container->removeDefinition('doctrine.dbal.idle_connection_listener');
249+
$container->removeDefinition('doctrine.dbal.idle_connection_middleware');
254250
}
255251

256252
/**
@@ -1196,12 +1192,14 @@ private function createArrayAdapterCachePool(ContainerBuilder $container, string
11961192
* @param string[] $connWithLogging
11971193
* @param string[] $connWithProfiling
11981194
* @param string[] $connWithBacktrace
1195+
* @param string[] $connWithTtl
11991196
*/
12001197
private function registerDbalMiddlewares(
12011198
ContainerBuilder $container,
12021199
array $connWithLogging,
12031200
array $connWithProfiling,
1204-
array $connWithBacktrace
1201+
array $connWithBacktrace,
1202+
array $connWithTtl
12051203
): void {
12061204
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
12071205
$loader->load('middlewares.xml');
@@ -1217,5 +1215,11 @@ private function registerDbalMiddlewares(
12171215
$debugMiddlewareAbstractDef
12181216
->addTag('doctrine.middleware', ['connection' => $connName]);
12191217
}
1218+
1219+
$idleConnectionMiddlewareAbstractDef = $container->getDefinition('doctrine.dbal.idle_connection_middleware');
1220+
foreach ($connWithTtl as $connName) {
1221+
$idleConnectionMiddlewareAbstractDef
1222+
->addTag('doctrine.middleware', ['connection' => $connName, 'priority' => 10]);
1223+
}
12201224
}
12211225
}
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Doctrine\Bundle\DoctrineBundle\Middleware;
4+
5+
use ArrayObject;
6+
use Doctrine\DBAL\Driver;
7+
use Doctrine\DBAL\Driver\Middleware;
8+
use Symfony\Bridge\Doctrine\Middleware\IdleConnection\Driver as IdleConnectionDriver;
9+
10+
class IdleConnectionMiddleware implements Middleware, ConnectionNameAwareInterface
11+
{
12+
private ArrayObject $connectionExpiries;
13+
/** @var array<string, int> */
14+
private array $ttlByConnection;
15+
private string $connectionName;
16+
17+
/**
18+
* @param ArrayObject<string, int> $connectionExpiries
19+
* @param array<string, int> $ttlByConnection
20+
*/
21+
public function __construct(ArrayObject $connectionExpiries, array $ttlByConnection)
22+
{
23+
$this->connectionExpiries = $connectionExpiries;
24+
$this->ttlByConnection = $ttlByConnection;
25+
}
26+
27+
public function setConnectionName(string $name): void
28+
{
29+
$this->connectionName = $name;
30+
}
31+
32+
public function wrap(Driver $driver): Driver
33+
{
34+
return new IdleConnectionDriver($driver, $this->connectionExpiries, $this->ttlByConnection[$this->connectionName], $this->connectionName);
35+
}
36+
}

Resources/config/dbal.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,9 @@
101101
<tag name="controller.service_arguments" />
102102
</service>
103103

104-
<service id="doctrine.listeners.doctrine_connection_listener" class="Symfony\Bridge\Doctrine\Listener\ConnectionListener">
104+
<service id="doctrine.dbal.idle_connection_listener" class="Symfony\Bridge\Doctrine\Middleware\IdleConnection\Listener">
105+
<argument type="service" id="doctrine.dbal.connection_expiries" />
105106
<argument type="service" id="service_container" />
106-
<argument /> <!-- check timing -->
107107
<tag name="kernel.event_subscriber" />
108108
</service>
109109

Resources/config/middlewares.xml

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
66

77
<services>
8+
<service id="doctrine.dbal.connection_expiries" class="ArrayObject"/>
89
<service id="doctrine.dbal.logging_middleware" class="Doctrine\DBAL\Logging\Middleware" abstract="true">
910
<argument type="service" id="logger" />
1011
<tag name="monolog.logger" channel="doctrine" />
@@ -17,5 +18,9 @@
1718
<argument type="service" id="doctrine.debug_data_holder" />
1819
<argument type="service" id="debug.stopwatch" on-invalid="null" />
1920
</service>
21+
<service id="doctrine.dbal.idle_connection_middleware" class="Doctrine\Bundle\DoctrineBundle\Middleware\IdleConnectionMiddleware" abstract="true">
22+
<argument type="service" id="doctrine.dbal.connection_expiries" />
23+
<argument /> <!-- check timing -->
24+
</service>
2025
</services>
2126
</container>

Tests/DependencyInjection/AbstractDoctrineExtensionTest.php

+4
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ public function testDbalLoadSinglePrimaryReplicaConnection(): void
220220
'host' => 'localhost',
221221
'unix_socket' => '/path/to/mysqld.sock',
222222
'driverOptions' => [PDO::ATTR_STRINGIFY_FETCHES => 1],
223+
'idle_connection_ttl' => 600,
223224
],
224225
$param['primary'],
225226
);
@@ -336,6 +337,7 @@ public function testLoadSimpleSingleConnection(): void
336337
'driver' => 'pdo_mysql',
337338
'driverOptions' => [],
338339
'defaultTableOptions' => [],
340+
'idle_connection_ttl' => 600,
339341
],
340342
new Reference('doctrine.dbal.default_connection.configuration'),
341343
method_exists(Connection::class, 'getEventManager')
@@ -375,6 +377,7 @@ public function testLoadSimpleSingleConnectionWithoutDbName(): void
375377
'driver' => 'pdo_mysql',
376378
'driverOptions' => [],
377379
'defaultTableOptions' => [],
380+
'idle_connection_ttl' => 600,
378381
],
379382
new Reference('doctrine.dbal.default_connection.configuration'),
380383
method_exists(Connection::class, 'getEventManager')
@@ -414,6 +417,7 @@ public function testLoadSingleConnection(): void
414417
'dbname' => 'sqlite_db',
415418
'memory' => true,
416419
'defaultTableOptions' => [],
420+
'idle_connection_ttl' => 600,
417421
],
418422
new Reference('doctrine.dbal.default_connection.configuration'),
419423
method_exists(Connection::class, 'getEventManager')

Tests/DependencyInjection/DoctrineExtensionTest.php

+50
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,56 @@ public function testDefinitionsToLogQueriesLoggingFalse(): void
14201420
$this->assertArrayNotHasKey('doctrine.middleware', $abstractMiddlewareDefTags);
14211421
}
14221422

1423+
public function testDefinitionsIdleConnection(): void
1424+
{
1425+
$container = $this->getContainer();
1426+
$extension = new DoctrineExtension();
1427+
1428+
$config = BundleConfigurationBuilder::createBuilder()
1429+
->addConnection([
1430+
'connections' => [
1431+
'conn1' => [
1432+
'password' => 'foo',
1433+
'logging' => false,
1434+
'profiling' => false,
1435+
'idle_connection_ttl' => 15,
1436+
],
1437+
'conn2' => [
1438+
'password' => 'bar',
1439+
'logging' => false,
1440+
'profiling' => true,
1441+
],
1442+
],
1443+
])
1444+
->build();
1445+
1446+
$extension->load([$config], $container);
1447+
1448+
$this->assertTrue($container->hasDefinition('doctrine.dbal.idle_connection_middleware'));
1449+
1450+
$abstractMiddlewareDef = $container->getDefinition('doctrine.dbal.idle_connection_middleware');
1451+
$ttlByConnection = $abstractMiddlewareDef->getArgument(1);
1452+
1453+
$this->assertArrayHasKey('conn1', $ttlByConnection);
1454+
$this->assertEquals(15, $ttlByConnection['conn1']);
1455+
$this->assertArrayHasKey('conn2', $ttlByConnection);
1456+
$this->assertEquals(600, $ttlByConnection['conn2']);
1457+
1458+
$abstractMiddlewareDefTags = $container->getDefinition('doctrine.dbal.idle_connection_middleware')->getTags();
1459+
1460+
$idleConnectionMiddlewareTagAttributes = [];
1461+
foreach ($abstractMiddlewareDefTags as $tag => $attributes) {
1462+
if ($tag !== 'doctrine.middleware') {
1463+
continue;
1464+
}
1465+
1466+
$idleConnectionMiddlewareTagAttributes = $attributes;
1467+
}
1468+
1469+
$this->assertTrue(in_array(['connection' => 'conn1', 'priority' => 10], $idleConnectionMiddlewareTagAttributes, true), 'Tag with connection conn1 not found for doctrine.dbal.idle_connection_middleware');
1470+
$this->assertTrue(in_array(['connection' => 'conn2', 'priority' => 10], $idleConnectionMiddlewareTagAttributes, true), 'Tag with connection conn2 found for doctrine.dbal.idle_connection_middleware');
1471+
}
1472+
14231473
/**
14241474
* @requires function \Symfony\Bridge\Doctrine\ArgumentResolver\EntityValueResolver::__construct
14251475
* @testWith [true]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Doctrine\Bundle\DoctrineBundle\Tests\Middleware;
4+
5+
use ArrayObject;
6+
use Doctrine\Bundle\DoctrineBundle\Middleware\IdleConnectionMiddleware;
7+
use Doctrine\DBAL\Driver;
8+
use PHPUnit\Framework\TestCase;
9+
use Symfony\Bridge\Doctrine\Middleware\IdleConnection\Driver as IdleConnectionDriver;
10+
11+
use function time;
12+
13+
class IdleConnectionMiddlewareTest extends TestCase
14+
{
15+
public function testWrap()
16+
{
17+
$connectionExpiries = new ArrayObject(['connectionone' => time() - 30, 'connectiontwo' => time() + 40]);
18+
$ttlByConnection = ['connectionone' => 25, 'connectiontwo' => 60];
19+
20+
$middleware = new IdleConnectionMiddleware($connectionExpiries, $ttlByConnection);
21+
$middleware->setConnectionName('connectionone');
22+
23+
$driverMock = $this->createMock(Driver::class);
24+
$wrappedDriver = $middleware->wrap($driverMock);
25+
26+
$this->assertInstanceOf(IdleConnectionDriver::class, $wrappedDriver);
27+
}
28+
}

0 commit comments

Comments
 (0)