How can I get php pdo code to keep retrying to connect if there are too many open connections?

StackOverflow https://stackoverflow.com/questions/14929968

  •  10-03-2022
  •  | 
  •  

Question

I have an issue, it has only cropped up now. I am on a shared web hosting plan that has a maximum of 10 concurrent database connections. The web app has dozens of queries, some pdo, some mysql_*.

Loading one page in particular peaks at 5-6 concurrent connections meaning it takes a minimum of 2 users loading it at the same time to spit an error on one or both of them.

I know this is inefficient, I'm sure I can cut that down quite a bit, but that's what my idea is at the moment is to move the pdo code into a function and just pass in a query string and an array of variables, then have it return an array (partly to tidy my code).

THE ACTUAL QUESTION:

How can I get this function to continue to retry until it manages to execute, and hold up the script that called it (and any script that might have called that one) until it manages to execute and return it's data? I don't want things executing out of order, I am happy with code being delayed for a second or so during peak times

Since someone will ask for code, here's what I do at the moment. I have this in a file on it's own so I have a central place to change connection parameters. the if statement is merely to remove the need to continuously change the parameters when I switch from my test server to the liver server

$dbtype = "mysql";
$server_addr = $_SERVER['SERVER_ADDR'];
if ($server_addr == '192.168.1.10') {
    $dbhost = "localhost";
} else {
    $dbhost = "xxxxx.xxxxx.xxxxx.co.nz";
}
$dbname = "mydatabase";
$dbuser = "user";
$dbpass = "supersecretpassword";

I 'include' that file at the top of a function

 include 'db_connection_params.php';
        $pdo_conn = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);

then run commands like this all on the one connection

$sql = "select * from tbl_sub_cargo_cap where sub_model_sk = ?";
$capq = $pdo_conn->prepare($sql);
$capq->execute(array($sk_to_load));
while ($caprow = $capq->fetch(PDO::FETCH_ASSOC)) {
//stuff
}
Était-ce utile?

La solution

You shouldn't need 5-6 concurrent connections for a single page, each page should only really ever use 1 connection. I'd try to re-architect whatever part of your application is causing multiple connections on a single page.

However, you should be able to catch a PDOException when the connection fails (documentation on connection management), and then retry some number of times.

A quick example,

<?php
$retries = 3;
while ($retries > 0)
{
    try
    {
        $dbh = new PDO("mysql:host=localhost;dbname=blahblah", $user, $pass);
        // Do query, etc.
        $retries = 0;
    }
    catch (PDOException $e)
    {
        // Should probably check $e is a connection error, could be a query error!
        echo "Something went wrong, retrying...";
        $retries--;
        usleep(500); // Wait 0.5s between retries.
    }
}

Autres conseils

10 concurrent connections is A LOT. It can serve 10-15 online users easily. Heavy efforts needed to exhaust them.
So there is something wrong with your code.

There are 2 main reasons for it:

  • slow queries take too much time and thus serving one hit uses one mysql connection for too long.
  • multiple connections opened from every script.

The former one have to be investigated but for the latter one it's simple:

  1. Do not mix myqsl_ and PDO in one script: you are opening 2 connections at a time.
  2. When using PDO, open connection only once and then use it throughout your code.

Reducing the number of connections in one script is the only way to go.
If you have multiple instances of PDO class in your code, you will need to add that timeout handling code you want to every call. So, heavy code rewriting required anyway.
Replace these new instances with global $pdo; instead. It will take the same amount of time but it will be permanent solution, not temporary patch as you want it.
Please be sensible.

PHP automatically closes all the connections st the end of the script, you don't have to care about closing them manually.
Having only one connection throughout one script is a common practice. It is used by ALL the developers around the world. You can use it without any doubts. Just use it.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top