In Illuminate/Database/Connectors/Connector.php
protected function createPdoConnection($dsn, $username, $password, $options)
{
if (class_exists(PDOConnection::class) && ! $this->isPersistentConnection($options)) {
return new PDOConnection($dsn, $username, $password, $options);
}
return new PDO($dsn, $username, $password, $options);
}
The above function will execute forever at new PDO($dsn, $username, $password, $options)
at a high packet loss rate network environment.
What I want is to not continue waiting for that after 30 seconds and return error/throw an exception (for clarification of why I want this: after that my application will try to connect to other slave databases instead).
The base line is that I don't think I should modify any code in Vendor.
The logic of generating the $options
variable is set inside config/database.php
and I did the following:
'options' => extension_loaded('pdo_mysql') ? array_filter([
...
PDO::ATTR_TIMEOUT => 1,
]) : [],
The result is that an exception will be thrown but will be caught in the same Connector.php
in the following function:
public function createConnection($dsn, array $config, array $options)
{
[$username, $password] = [
$config['username'] ?? null, $config['password'] ?? null,
];
try {
return $this->createPdoConnection(
$dsn, $username, $password, $options
);
} catch (Exception $e) {
return $this->tryAgainIfCausedByLostConnection(
$e, $dsn, $username, $password, $options
);
}
}
And the new PDO()
line will be executed again. Basically there are some similar try catch things after that but essentially it never actually throws the exception into the application code but keeps reconnecting.
EDIT:
Actually I found out the Laravel code actually throws the exception after 4 retries but in most of times one of the retry will not throw the exception properly despite PDO::ATTR_TIMEOUT
being set. PDO::ATTR_ERRMODE
is also tried but it does not change.
I am suspecting that since the packet loss rate is 95% and not 100%, the connection is in the process of being established but at a very slow rate.
So I guess my question now is, is there a way to force kill an establishing connection after a timeout?