Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f7cc44e

Browse filesBrowse files
alli83nicolas-grekas
authored andcommitted
[DoctrineBridge] Idle connection listener for long running runtime
1 parent 02c1e3c commit f7cc44e
Copy full SHA for f7cc44e

File tree

7 files changed

+192
-8
lines changed
Filter options

7 files changed

+192
-8
lines changed

‎phpunit.xml.dist

Copy file name to clipboardExpand all lines: phpunit.xml.dist
+8-7Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,14 @@
7575
<array>
7676
<element key="0"><string>Cache\IntegrationTests</string></element>
7777
<element key="1"><string>Symfony\Bridge\Doctrine\Middleware\Debug</string></element>
78-
<element key="2"><string>Symfony\Component\Cache</string></element>
79-
<element key="3"><string>Symfony\Component\Cache\Tests\Fixtures</string></element>
80-
<element key="4"><string>Symfony\Component\Cache\Tests\Traits</string></element>
81-
<element key="5"><string>Symfony\Component\Cache\Traits</string></element>
82-
<element key="6"><string>Symfony\Component\Console</string></element>
83-
<element key="7"><string>Symfony\Component\HttpFoundation</string></element>
84-
<element key="8"><string>Symfony\Component\Uid</string></element>
78+
<element key="2"><string>Symfony\Bridge\Doctrine\Middleware\IdleConnection</string></element>
79+
<element key="3"><string>Symfony\Component\Cache</string></element>
80+
<element key="4"><string>Symfony\Component\Cache\Tests\Fixtures</string></element>
81+
<element key="5"><string>Symfony\Component\Cache\Tests\Traits</string></element>
82+
<element key="6"><string>Symfony\Component\Cache\Traits</string></element>
83+
<element key="7"><string>Symfony\Component\Console</string></element>
84+
<element key="8"><string>Symfony\Component\HttpFoundation</string></element>
85+
<element key="9"><string>Symfony\Component\Uid</string></element>
8586
</array>
8687
</element>
8788
</array>

‎src/Symfony/Bridge/Doctrine/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* Deprecate the `DoctrineExtractor::getTypes()` method, use `DoctrineExtractor::getType()` instead
88
* Allow `EntityValueResolver` to return a list of entities
9+
* Add support for auto-closing idle connections
910

1011
7.0
1112
---
+37Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Doctrine\Middleware\IdleConnection;
13+
14+
use Doctrine\DBAL\Driver as DriverInterface;
15+
use Doctrine\DBAL\Driver\Connection as ConnectionInterface;
16+
use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware;
17+
18+
final class Driver extends AbstractDriverMiddleware
19+
{
20+
public function __construct(
21+
DriverInterface $driver,
22+
private \ArrayObject $connectionExpiries,
23+
private readonly int $ttl,
24+
private readonly string $connectionName,
25+
) {
26+
parent::__construct($driver);
27+
}
28+
29+
public function connect(array $params): ConnectionInterface
30+
{
31+
$timestamp = time();
32+
$connection = parent::connect($params);
33+
$this->connectionExpiries[$this->connectionName] = $timestamp + $this->ttl;
34+
35+
return $connection;
36+
}
37+
}
+55Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Doctrine\Middleware\IdleConnection;
13+
14+
use Symfony\Component\DependencyInjection\ContainerInterface;
15+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
16+
use Symfony\Component\HttpKernel\Event\RequestEvent;
17+
use Symfony\Component\HttpKernel\KernelEvents;
18+
19+
final class Listener implements EventSubscriberInterface
20+
{
21+
/**
22+
* @param \ArrayObject<string, int> $connectionExpiries
23+
*/
24+
public function __construct(
25+
private readonly \ArrayObject $connectionExpiries,
26+
private ContainerInterface $container,
27+
) {
28+
}
29+
30+
public function onKernelRequest(RequestEvent $event): void
31+
{
32+
$timestamp = time();
33+
34+
foreach ($this->connectionExpiries as $name => $expiry) {
35+
if ($timestamp >= $expiry) {
36+
// unset before so that we won't retry in case of any failure
37+
$this->connectionExpiries->offsetUnset($name);
38+
39+
try {
40+
$connection = $this->container->get("doctrine.dbal.{$name}_connection");
41+
$connection->close();
42+
} catch (\Exception) {
43+
// ignore exceptions to remain fail-safe
44+
}
45+
}
46+
}
47+
}
48+
49+
public static function getSubscribedEvents(): array
50+
{
51+
return [
52+
KernelEvents::REQUEST => 'onKernelRequest',
53+
];
54+
}
55+
}
+42Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Doctrine\Tests\Middleware\IdleConnection;
13+
14+
use Doctrine\DBAL\Driver as DriverInterface;
15+
use Doctrine\DBAL\Driver\Connection as ConnectionInterface;
16+
use PHPUnit\Framework\TestCase;
17+
use Symfony\Bridge\Doctrine\Middleware\IdleConnection\Driver;
18+
19+
class DriverTest extends TestCase
20+
{
21+
/**
22+
* @group time-sensitive
23+
*/
24+
public function testConnect()
25+
{
26+
$driverMock = $this->createMock(DriverInterface::class);
27+
$connectionMock = $this->createMock(ConnectionInterface::class);
28+
29+
$driverMock->expects($this->once())
30+
->method('connect')
31+
->willReturn($connectionMock);
32+
33+
$connectionExpiries = new \ArrayObject();
34+
35+
$driver = new Driver($driverMock, $connectionExpiries, 60, 'default');
36+
$connection = $driver->connect([]);
37+
38+
$this->assertSame($connectionMock, $connection);
39+
$this->assertArrayHasKey('default', $connectionExpiries);
40+
$this->assertSame(time() + 60, $connectionExpiries['default']);
41+
}
42+
}
+43Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Middleware\IdleConnection;
13+
14+
use Doctrine\DBAL\Connection as ConnectionInterface;
15+
use PHPUnit\Framework\TestCase;
16+
use Symfony\Bridge\Doctrine\Middleware\IdleConnection\Listener;
17+
use Symfony\Component\DependencyInjection\ContainerInterface;
18+
use Symfony\Component\HttpKernel\Event\RequestEvent;
19+
20+
class ListenerTest extends TestCase
21+
{
22+
public function testOnKernelRequest()
23+
{
24+
$containerMock = $this->createMock(ContainerInterface::class);
25+
$connectionExpiries = new \ArrayObject(['connectionone' => time() - 30, 'connectiontwo' => time() + 40]);
26+
27+
$connectionOneMock = $this->getMockBuilder(ConnectionInterface::class)
28+
->disableOriginalConstructor()
29+
->getMock();
30+
31+
$containerMock->expects($this->exactly(1))
32+
->method('get')
33+
->with('doctrine.dbal.connectionone_connection')
34+
->willReturn($connectionOneMock);
35+
36+
$listener = new Listener($connectionExpiries, $containerMock);
37+
38+
$listener->onKernelRequest($this->createMock(RequestEvent::class));
39+
40+
$this->assertArrayNotHasKey('connectionone', (array) $connectionExpiries);
41+
$this->assertArrayHasKey('connectiontwo', (array) $connectionExpiries);
42+
}
43+
}

‎src/Symfony/Bridge/Doctrine/phpunit.xml.dist

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/phpunit.xml.dist
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@
3333
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener">
3434
<arguments>
3535
<array>
36-
<element key="time-sensitive"><string>Symfony\Bridge\Doctrine\Middleware\Debug</string></element>
36+
<element key="time-sensitive">
37+
<array>
38+
<element key="0"><string>Symfony\Bridge\Doctrine\Middleware\Debug</string></element>
39+
<element key="1"><string>Symfony\Bridge\Doctrine\Middleware\Debug</string></element>
40+
</array>
41+
</element>
3742
</array>
3843
</arguments>
3944
</listener>

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.