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

#22 - switching native PDO to custom PersistentPDO which prevents timeouts #30

Merged
merged 2 commits into from
Jun 30, 2022
Merged
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
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"description": "A database production to sandbox utility to sanitize data.",
"type": "library",
"require": {
"ext-pdo": "*",
"php-di/php-di": "^6.0",
"aws/aws-sdk-php": "^3.19",
"symfony/yaml": ">=2.3",
Expand Down
2 changes: 1 addition & 1 deletion src/Engines/ConnectionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ interface ConnectionInterface
{
public function isAvailable(): bool;

public function getConnection(): \PDO;
public function getConnection(): ReconnectingPDO;

public function getDSN(): string;

Expand Down
34 changes: 10 additions & 24 deletions src/Engines/ConnectionTrait.php
Original file line number Diff line number Diff line change
@@ -1,41 +1,27 @@
<?php
/**
* SwiftOtter_Base is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SwiftOtter_Base is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with SwiftOtter_Base. If not, see <http://www.gnu.org/licenses/>.
*
* @author Joseph Maxwell
* @copyright SwiftOtter Studios, 12/3/16
* @package default
**/

declare(strict_types=1);

namespace Driver\Engines;

use PDO;

trait ConnectionTrait
{
private $connection;
private ?ReconnectingPDO $connection = null;

public function getConnection(): \PDO
public function getConnection(): ReconnectingPDO
{
if (!$this->connection) {
$options = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
];

$this->connection = new \PDO($this->getDSN(), $this->getUser(), $this->getPassword(), $options);
$this->connection = new ReconnectingPDO($this->getDSN(), $this->getUser(), $this->getPassword(), $options);
}

return $this->connection;
}
}
}
3 changes: 2 additions & 1 deletion src/Engines/MySql/Transformation.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

use Driver\Commands\CommandInterface;
use Driver\Engines\MySql\Sandbox\Utilities;
use Driver\Engines\ReconnectingPDO;
use Driver\Engines\RemoteConnectionInterface;
use Driver\Pipeline\Environment\EnvironmentInterface;
use Driver\Pipeline\Transport\Status;
Expand Down Expand Up @@ -71,7 +72,7 @@ public function getProperties()
return $this->properties;
}

private function applyTransformationsTo(\PDO $connection, $transformations)
private function applyTransformationsTo(ReconnectingPDO $connection, $transformations)
{
array_walk($transformations, function ($query) use ($connection) {
try {
Expand Down
87 changes: 87 additions & 0 deletions src/Engines/ReconnectingPDO.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

declare(strict_types=1);

namespace Driver\Engines;

use PDO;
use PDOException;
use PDOStatement;

/**
* @method PDOStatement|false prepare($query, array $options = [])
* @method bool beginTransaction()
* @method bool commit()
* @method bool rollBack()
* @method bool inTransaction()
* @method bool setAttribute(int $attribute, $value)
* @method int|false exec(string $statement)
* @method PDOStatement|false query(string $statement, int $mode = PDO::ATTR_DEFAULT_FETCH_MODE, $arg3 = null, array $ctorargs = [])
* @method string|false lastInsertId(?string $name)
* @method mixed errorCode()
* @method array errorInfo()
* @method mixed getAttribute(int $attribute)
* @method string|false quote(string $string, int $type = PDO::PARAM_STR)
* @method static array getAvailableDrivers()
* @method bool sqliteCreateFunction($function_name, $callback, int $num_args = -1, int $flags = 0)
* @method bool pgsqlCopyFromArray(string $tableName, array $rows, string $separator, string $nullAs, ?string $fields)
* @method bool pgsqlCopyFromFile(string $tableName, string $filename, string $separator = "\t", string $nullAs = "\\\\N", ?string $fields = null)
* @method array|false pgsqlCopyToArray(string $tableName, string $separator = "\t", string $nullAs = "\\\\N", ?string $fields = null)
* @method bool pgsqlCopyToFile(string $tableName, string $filename, string $separator = "\t", string $nullAs = "\\\\N", ?string $fields = null)
* @method string|false pgsqlLOBCreate()
* @method resource|false pgsqlLOBOpen(string $oid, string $mode = "rb")
* @method bool pgsqlLOBUnlink(string $oid)
* @method array|false pgsqlGetNotify(int $fetchMode = 0, int $timeoutMilliseconds = 0)
* @method int pgsqlGetPid()
*/
class ReconnectingPDO
{
private const MYSQL_GENERAL_ERROR_CODE = 'HY000';
private const SERVER_HAS_GONE_AWAY_ERROR_CODE = 2006;

private string $dsn;
private ?string $username;
private ?string $password;
private ?array $options;
private PDO $pdo;

/**
* @throws PDOException
*/
public function __construct(string $dsn, ?string $username = null, ?string $password = null, ?array $options = null)
{
$this->dsn = $dsn;
$this->username = $username;
$this->password = $password;
$this->options = $options;
$this->pdo = $this->createPDO();
}

/**
* @throws PDOException
*/
public function __call(string $name, array $arguments)
{
try {
$this->pdo->query('SELECT 1')->fetchColumn();
} catch (PDOException $e) {
if ($e->errorInfo[0] !== self::MYSQL_GENERAL_ERROR_CODE
|| $e->errorInfo[1] !== self::SERVER_HAS_GONE_AWAY_ERROR_CODE
) {
throw $e;
}
$this->pdo = $this->createPDO();
}
return $this->pdo->$name(...$arguments);
}

/**
* @throws PDOException
*/
private function createPDO(): PDO
{
$pdo = new PDO($this->dsn, $this->username, $this->password, $this->options);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $pdo;
}
}
3 changes: 2 additions & 1 deletion src/System/LocalConnectionLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use DI\Container;
use Driver\Engines\ConnectionInterface;
use Driver\Engines\LocalConnectionInterface;
use Driver\Engines\ReconnectingPDO;

class LocalConnectionLoader implements LocalConnectionInterface
{
Expand All @@ -35,7 +36,7 @@ public function __construct(
$this->container = $container;
}

public function getConnection(): \PDO
public function getConnection(): ReconnectingPDO
{
return $this->get()->getConnection();
}
Expand Down