Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delay mechanism #59

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ $connectionParams = array(
'wrapperClass' => 'Facile\DoctrineMySQLComeBack\Doctrine\DBAL\Connection',
'driverClass' => 'Facile\DoctrineMySQLComeBack\Doctrine\DBAL\Driver\PDOMySql\Driver',
'driverOptions' => array(
'x_reconnect_attempts' => 3
'x_reconnect_attempts' => 3,
'x_reconnect_delay' => 1000000 // microseconds
)
);

Expand Down Expand Up @@ -69,6 +70,8 @@ doctrine:
driver_class: 'Facile\DoctrineMySQLComeBack\Doctrine\DBAL\Driver\PDOMySql\Driver'
options:
x_reconnect_attempts: 3
# microseconds
x_reconnect_delay: 1000000
```

If you are setting up your database connection using a DSN/`database_url` env variable (like the Doctrine Symfony Flex recipe suggests) **you need to remove the protocol** from your database url.
Expand All @@ -87,6 +90,8 @@ doctrine:
driver_class: 'Facile\DoctrineMySQLComeBack\Doctrine\DBAL\Driver\PDOMySql\Driver'
options:
x_reconnect_attempts: 3
# microseconds
x_reconnect_delay: 1000000

```

Expand All @@ -108,6 +113,7 @@ return [
'charset' => 'UTF8',
'driverOptions' => [
'x_reconnect_attempts' => 9,
'x_reconnect_delay' => 1000000 // microseconds
]
],
],
Expand Down
21 changes: 20 additions & 1 deletion src/ConnectionTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ trait ConnectionTrait
/** @var int */
protected $reconnectAttempts = 0;

/** @var int */
private $reconnectDelay = 0;

/** @var ReflectionProperty|null */
private $selfReflectionNestingLevelProperty;

Expand Down Expand Up @@ -56,6 +59,10 @@ public function __construct(
$this->reconnectAttempts = (int)$params['driverOptions']['x_reconnect_attempts'];
}

if (isset($params['driverOptions']['x_reconnect_delay'])) {
$this->reconnectDelay = (int)$params['driverOptions']['x_reconnect_delay'];
}

parent::__construct($params, $driver, $config, $eventManager);
}

Expand All @@ -81,6 +88,7 @@ public function executeQuery($query, array $params = array(), $types = array(),
} catch (Exception $e) {
if ($this->canTryAgain($attempt) && $this->isRetryableException($e, $query)) {
$this->close();
$this->delayReconnection();
++$attempt;
$retry = true;
} else {
Expand Down Expand Up @@ -109,6 +117,7 @@ public function query()
} catch (Exception $e) {
if ($this->canTryAgain($attempt) && $this->isRetryableException($e, $args[0])) {
$this->close();
$this->delayReconnection();
++$attempt;
$retry = true;
} else {
Expand Down Expand Up @@ -148,6 +157,7 @@ public function executeStatement($sql, array $params = [], array $types = [])
} catch (Exception $e) {
if ($this->canTryAgain($attempt) && $this->isRetryableException($e)) {
$this->close();
$this->delayReconnection();
++$attempt;
$retry = true;
} else {
Expand Down Expand Up @@ -178,6 +188,7 @@ public function beginTransaction()
} catch (Exception $e) {
if ($this->canTryAgain($attempt, true) && $this->_driver->isGoneAwayException($e)) {
$this->close();
$this->delayReconnection();
if (0 < $this->getTransactionNestingLevel()) {
$this->resetTransactionNestingLevel();
}
Expand Down Expand Up @@ -279,6 +290,14 @@ private function resetTransactionNestingLevel()
$this->selfReflectionNestingLevelProperty->setValue($this, 0);
}

/**
* @return void
*/
public function delayReconnection()
{
usleep($this->reconnectDelay);
}

/**
* @param string $query
*
Expand All @@ -288,4 +307,4 @@ public function isUpdateQuery($query)
{
return !preg_match('/^[\s\n\r\t(]*(select|show|describe)[\s\n\r\t(]+/i', $query);
}
}
}
1 change: 1 addition & 0 deletions src/Driver/Mysqli/Driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Driver extends \Doctrine\DBAL\Driver\Mysqli\Driver implements ServerGoneAw
*/
private $extendedDriverOptions = [
'x_reconnect_attempts',
'x_reconnect_delay'
];

/**
Expand Down
2 changes: 2 additions & 0 deletions src/Statement.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function __construct($sql, ConnectionInterface $conn)
} catch (\Exception $e) {
if ($conn->canTryAgain($attempt) && $conn->isRetryableException($e, $sql)) {
$conn->close();
$conn->delayReconnection();
++$attempt;
$retry = true;
} else {
Expand Down Expand Up @@ -95,6 +96,7 @@ public function execute($params = null)
} catch (\Exception $e) {
if ($this->conn->canTryAgain($attempt) && $this->conn->isRetryableException($e, $this->sql)) {
$this->conn->close();
$this->conn->delayReconnection($attempt);
$this->recreateStatement();
++$attempt;
$retry = true;
Expand Down
32 changes: 27 additions & 5 deletions tests/functional/AbstractFunctionalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@

abstract class AbstractFunctionalTest extends TestCase
{
abstract protected function createConnection(int $attempts): Connection;
abstract protected function createConnection(int $attempts, int $delay): Connection;

protected function getConnectedConnection(int $attempts): Connection
protected function getConnectedConnection(int $attempts, int $delay = 0): Connection
{
$connection = $this->createConnection($attempts);
$connection = $this->createConnection($attempts, $delay);
$connection->query('SELECT 1');

return $connection;
Expand Down Expand Up @@ -51,7 +51,7 @@ protected function getConnectionParams(): array
/**
* Disconnect other sessions
*/
protected function forceDisconnect(\Doctrine\DBAL\Connection $connection): void
protected function forceDisconnect(\Doctrine\DBAL\Connection $connection, int $delay = 0): void
{
/** @var Connection $connection */
$connection2 = DriverManager::getConnection(array_merge(
Expand All @@ -60,7 +60,8 @@ protected function forceDisconnect(\Doctrine\DBAL\Connection $connection): void
'wrapperClass' => Connection::class,
'driverClass' => Driver::class,
'driverOptions' => array(
'x_reconnect_attempts' => 1
'x_reconnect_attempts' => 1,
'x_reconnect_delay' => $delay,
)
]
));
Expand Down Expand Up @@ -94,6 +95,27 @@ public function testExecuteQueryShouldReconnect(): void
$this->assertSame(2, $connection->connectCount);
}

public function testExecuteQueryShouldReconnectWithDelay(): void
{
$delay = 2000000;

$preTiming = microtime(true);
$connection = $this->getConnectedConnection(1, $delay);
$this->assertSame(1, $connection->connectCount);
$this->forceDisconnect($connection, $delay);

$connection->executeQuery('SELECT 1')->fetch();
$this->assertSame(2, $connection->connectCount);
$this->forceDisconnect($connection, $delay);

$connection->executeQuery('SELECT 1')->fetch();
$this->assertSame(3, $connection->connectCount);

// If
$postTiming = microtime(true);
$this->assertGreaterThanOrEqual(4, $postTiming - $preTiming);
}

public function testQueryShouldReconnect(): void
{
$connection = $this->getConnectedConnection(1);
Expand Down
5 changes: 3 additions & 2 deletions tests/functional/MysqliTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class MysqliTest extends AbstractFunctionalTest
{
protected function createConnection(int $attempts): Connection
protected function createConnection(int $attempts, int $delay): Connection
{
/** @var Connection $connection */
$connection = DriverManager::getConnection(array_merge(
Expand All @@ -18,7 +18,8 @@ protected function createConnection(int $attempts): Connection
'wrapperClass' => Connection::class,
'driverClass' => Driver::class,
'driverOptions' => array(
'x_reconnect_attempts' => $attempts
'x_reconnect_attempts' => $attempts,
'x_reconnect_delay' => $delay,
)
]
));
Expand Down
5 changes: 3 additions & 2 deletions tests/functional/PDOMySqlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class PDOMySqlTest extends AbstractFunctionalTest
{
protected function createConnection(int $attempts): Connection
protected function createConnection(int $attempts, int $delay): Connection
{
/** @var Connection $connection */
$connection = DriverManager::getConnection(array_merge(
Expand All @@ -18,7 +18,8 @@ protected function createConnection(int $attempts): Connection
'wrapperClass' => Connection::class,
'driverClass' => Driver::class,
'driverOptions' => array(
'x_reconnect_attempts' => $attempts
'x_reconnect_attempts' => $attempts,
'x_reconnect_delay' => $delay,
)
]
));
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/ConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ public function testConstructor(): void

$params = [
'driverOptions' => [
'x_reconnect_attempts' => 999
'x_reconnect_attempts' => 999,
'x_reconnect_delay' => 1000,
],
'platform' => $platform->reveal()
];
Expand Down