I get the following error:
Link to server lost, unable to reconnect
I have a mysql daemon coded, and I use mysql_pconnect to connect to mysql but after a while, I get the following error and the daemon stops functioning properly:
Link to server lost, unable to reconnect
What I do is the following:
while(true)
{
$connect = mysql_pconnect(...);
$db = mysql_select_db(...);
}
What can I do to prevent this? I need mysql connection to stay steady for the whole duration of the daemon - which may be forever.
You have a few choices.
But just as a precursor, you should try and move away from relying on mysql_* and start using the PDO instead.
Anyway...
When you open a mysql connection, it will stay "available" until the wait timeout has expired. What you are doing is constantly creating a new connection, (also without closing the other connection). This means you will either hit the server mysql limit, or your unix box socket limit very quickly.
Wait Timeout
You should first check with your server to see what this timeout is set to.
You might want to consider increasing it in your my.cnf if it is terribly low. The default period is 28800 seconds (if I recall correctly).
You can check by issuing this query:
SHOW variables like "%wait_timeout%"
You can then change the value in your my.cnf to increase it or you can also set it using
SET ##GLOBAL.wait_timeout=288000
SELECT 1
Okay, now, with a reasonable set timeout set, the "typical" way that you can make sure that you don't get the mysql has gone away message, is to just do a SELECT 1. This will do another query and make sure that the connection is held open.
And, the benefit of using the PDO is that you can then catch PDOExceptions which might be thrown when a SELECT 1 fails.
This means, that you can then try and connect again, if an exception is thrown, and then check again. If you can't connect after that then you should probably kill your daemon.
Here is some code.... you would clearly have to make your PDO object using a valid connection string.
// $pdo holds the connection and a PDO object.
try {
$pdo->execute("SELECT 1");
} catch (PDOException $e) {
// Mysql has gone away.
$pdo = null
$pdo = new PDO( $connectionString );
echo "Mysql has gone away - But we attempted to reconnect\n";
try {
$pdo->execute("SELECT 1");
} catch (PDOException $e) {
echo "Mysql has failed twice - Kill Daemon\n";
throw($e);
}
}
This is the solution that I would probably take.
You can easily substitute the SELECT 1 with your own query that you actually want to use. This is just an example.
Related
I have a php script that is used to store some info in a postgresql db. In this script I am using a function to store some logs about certain db operations. During tests I found out that my script will log my errors related to pg_connect function, only after 4-5 seconds - and this represents a big issue for me.
Below you can find my tests and the results:
Case 1 - no error in pg_connect function:
Log("START DBCONN - without errors");
$dbconn = pg_connect("host=$host dbname=$dbname user=$dbuser password=$dbpassword");
if(!$dbconn){
Log("ERROR: Could not connect to database");
}
Log("END");
Case 2 - error in pg_connect:
Log("START DBCONN - with errors");
$dbconn = pg_connect("host=$host12 dbname=$dbname user=$dbuser password=$dbpassword");
if(!$dbconn){
Log("ERROR: Could not connect to database");
}
Log("END");
Results
case 1:
[12-Jan-2016 09:31:21] START DBCONN - without errors
[12-Jan-2016 09:31:21] END
case 2:
[12-Jan-2016 09:31:59] START DBCONN - with errors
[12-Jan-2016 09:32:03] ERROR: Could not connect to database
[12-Jan-2016 09:32:03] END
Do you know a solution for this ? because, I couldn't find one, yet :(
Thanks for your help !
Depending on the nature of the errors, there may be different reasons for it:
If the username or password is wrong, the server may delay the negative response to make brute-forcing a valid combination more cumbersome.
If the host is not reachable, the tcp connect timeout may be several seconds.
Both issues are hard to fix in a clean way.
There are also error conditions which should not result in a delay, for example:
if the host is reachable, but the database server is not running (i.e. "Connection refused").
The time to fail in case of a non-responding remote host can be adjusted with the connect_timeout option in the pg_connect() call.
PHP's pg_connect() documentation does not give any detail on connect_timeout but it just passes it to libpq, the C client library, where it's documented as:
http://www.postgresql.org/docs/current/static/libpq-connect.html
connect_timeout
Maximum wait for connection, in seconds (write as a decimal integer string). Zero or not specified means wait indefinitely. It is
not recommended to use a timeout of less than 2 seconds.
However, the 4 seconds before failure shown in the question seem reasonable for a TCP problem. If you expect recurring network errors with your database host, maybe a local connection pooler like pgBouncer should be considered, to insulate the web environnement from these high-latency errors.
We are getting both a PDOException and warnings. These warnings are driving us crazy.
Warning: PDOStatement::execute(): MySQL server has gone away in /home/Database.php on line 120
Warning: PDOStatement::execute(): Error reading result set's header in /home/Database.php on line 120
Here is the code that does this -- this is just to simulate a connection going away:
$db = new PDO('mysql:dbname=' . $name . ';host=' . $host, $user, $pass);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$statement = $db->prepare('SET SESSION wait_timeout = 1');
$statement->execute();
sleep(3);
try {
$statement = $db->prepare('SELECT 1');
$statement->execute();
} catch (PDOException $e) {
echo 'Exception! Err #:' . $e->errorInfo[1] . PHP_EOL;
}
EDIT: The question is why does this generate a warning and an exception. The code above just generates both even though we specifically tell PDO to throw exceptions.
The code above makes it happen faster than waiting for our servers default wait_timeout.
EDIT 2: I'm not sure why this was closed. The question is WHY is PHP spawning both a Warning, and an Exception regardless of the PDO Error Level?
You set wait_timeout to 1 then you sleep 3, what will happen? MySql will close connection after one second and you will get error "Mysql Server has gone away" with next statement 'cause you sleep for 3.
http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_wait_timeout
edit
Question is duplicate of MySQL error 2006: mysql server has gone away
edit 2
Causes of this error:
low wait_timeout - solution: ping, reconnect or increase it too
large packets - solution: tune max_allowed_packet in my.cfg
PDO reconnect - simulate ping in PDO How do i ping the MySQL db and reconnect using PDO
edit 3 question updated
The only way (afaik) to get rid of these warnings is to set expected (eg. E_ERROR) error_reporting level. You could wrapped pdo calls up in for example to set E_ERROR before and reset to default after execution.
PDO logs warnings/errors for logs purposes (sic!) for further analytics. The attribute you set (by setAttribute or constructor) only changes error handling/behavior of pdo - throw or not:). These two things are separated.
To prevent this error I'd just add
$db->setAttribute(PDO::ATTR_TIMEOUT,ini_get('max_execution_time'));
to your ->setAttribute calls after creating the PDO object.
I don't really know if this really works, but it should work.
(didn't test it)
I've read in PDO manual that to close connection you should use the following:
$connection = null;
However, Some people suggested that since PHP 5.3 has a new GC, the following should be used:
unset($connection);
I need to know once and for all, which one is preferred, or are they the same?
They do the same thing. Unsetting the $pdo handle and setting it null both close the connection.
You can test this for yourself. Run the following script in one window, and in a second window open the MySQL client and run SHOW PROCESSLIST every couple of seconds to see when the connection disappears.
<?php
$pdo = new PDO(..);
sleep(10);
unset($pdo);
echo "pdo unset!\n";
sleep(10);
Then change unset($pdo) to $pdo=null; and run the test again.
<?php
$pdo = new PDO(..);
sleep(10);
$pdo = null;
echo "pdo set null!\n";
sleep(10);
The extra sleep() at the end is there to give you a moment to see that the connection has dropped, before the PHP script terminates (which would drop the connection anyway).
I stumbled with this. I have a PDO object that spans setup and teardown, and I can't find where there must be a remaining reference, as setting $pdo to null did not resolve the problem.
User Contributed Notes in http://php.net/manual/en/pdo.connections.php discusses the problem of delayed closure. Here they suggest killing the current connection:
$pdo->query('SELECT pg_terminate_backend(pg_backend_pid());');
$pdo = null;
This is for postgres. For mysql I have used:
$pdo->query('KILL CONNECTION CONNECTION_ID();');
using
$pdo = null; //is an assignment to null; the variable still declared in the memory.
but
unset($pdo); // will call the function to distroy also the adress "#" pointed by the variable.
so using unset is prefered.
Just don't bother with closing at all. PHP will close it for you all right.
Note that of course your application have to be sanely designed, without the need of reconnecting to different databases at a rate of machine-gun. And even in latter case, the method you are using to close would be the least problem. You are barking wrongest tree ever. Work the number of connections, not the way you are closing them.
We have several different servers running the same PHP scripts, all of which use PHP mysqli connections/functions, and we noticed that, on one new server, we started getting many MYSQL Gone Away errors.
wait_timeout in MYSQL is set to 300 seconds on all servers, and this is the length of time it takes before the connection drops on this particular server (i.e. a wait of 301 seconds between queries in the code below produces the error, but 299 seconds does not).
However, all servers also have mysqli.reconnect set to 1 (On). According to documentation, mysqli.reconnect should mean that the dropped connection is reconnected automatically, however it definitely isn't.
Here is a code snippet that I've run that demonstrates the issue. It works on all servers except this particular server:
$mysqli = new mysqli('ip', 'username', 'pass', 'db');
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$query = "SELECT * FROM table LIMIT 1";
$result = $mysqli->query($query) or die($mysqli->error.__LINE__);
sleep(301);
$query = "SELECT * FROM table LIMIT 1";
$result = $mysqli->query($query) or die($mysqli->error.__LINE__);
mysqli_close($mysqli);
print "Finished\n";
exit;
I have also re-written the test script to use mysqli_ping() (since the documentation states that this function should reconnect automatically if mysqli.reconnect is set to 1), however this still does not reconnect, and the second query always produces the error that MySQL has gone away.
All servers are running slightly different versions of PHP. The server that fails is running 5.3.21, other servers are running 5.3.0 and 5.3.10.
Turned out the issue was with the MYSQLND driver. Our service provider basically recompiled PHP, and this resolved the issue.
There is a php bug filed about this, resolved as wontfix: https://bugs.php.net/bug.php?id=52561
I just came across this while looking for info about the mysqli.reconnect setting. According to the manual:
https://www.php.net/manual/en/mysqli.configuration.php#ini.mysqli.reconnect
Note: This php.ini setting is ignored by the mysqlnd driver.
That didn't specify whether it meant that it always would, or always would not, auto-reconnect. "Would not" seemed more likely, which is confirmed by the comment above noting that it was not happening when the setting was 1.
My issue was that I wanted a way to know when the connection had died (for error-reporting purposes, and so I could implement selective retrying of a failed DB operation in only that case). I don't know if there's a more direct way to check whether a DB connection is alive, but I found my way to the mysqli::ping() method. Except, if it silently auto-reconnected, I wouldn't know it had happened.
So my solution is to save/disable/restore the setting along with using ping(), like this:
if (!$result) { // DB operation failed
$save = ini_get('mysqli.reconnect'); // save setting
ini_set('mysqli.reconnect', 0); // disable it
$connected = $mysqli->ping(); // check connection
ini_set('mysqli.reconnect', $save); // restore setting
}
if ($connected) {
// Failure was something else. Handle that...
} else {
// Failure was due to dropped connection.
// Explicitly reconnect.
// Ok to retry operation...
}
I'm trying to connect to an Oracle DB which is currently offline. When it's online it's not a problem, however, now that it's offline my program is getting hung up on the $connection = oci_connect() line and timing out. How do I simply check the connectio and bail out if it's not there?
Try this (fill in your ip and port):
if ( #fsockopen($db_ip,$db_port ) ) {
//connect to database
} else {
// didn't work
}
This gives you both a manual error, plus will return the actual error.
$connection = oci_connect() or die("Critical Error: Could not connect to database.\n\n". oci_error());
Make sure to test this as hopefully the Oracle error doesn't do something stupid like return the connection string (with your DB password) but I wouldn't assume until you see for yourself.
You could select null from dual.
OK, now I see what your asking, I think.
You want to know how to tell if a database is up before you connect to it?
You can use TNSPING to see if a database is up... ok, maybe that's not 100% accurate but it's a good indicator. go to a command prompt and type TNSPING and hit enter. So then you have to figure out how to call a command line tool from PHP.
Here is what I do in ASP.NET
Dim OracleConn As New OracleConnection(YOUR CONNECTION STRING HERE)
Try
OracleConn.Open()
OracleConn.Close()
Catch ex As Exception
Session("ErrorMessage") = "OracleConn: " & ex.Message
Response.Redirect("AccessDenied.aspx")
End Try
It doesnt necessarily say the DB is offline, but an exception will occur if the connection cannot be opened