I keep getting the following error from my code:
Database connect failed: PDO::__construct(): send of 12 bytes failed with errno=110 Connection timed out
This error persistently happens on an api. If that api keeps getting called a lot during the day this does not happen. Only when the api is not used for some time.
I can solve this by doing a php-fpm restart/reload, but this shouldn't be the solution.
Does anybody have any idea how to solve this?
--EDIT--
This is the code for connection to the database:
public function connectDatabase($allow_persistent = true)
{
$this->db = null;
$this->readINI();
$pdo_attr = [
PDO::ATTR_PERSISTENT => $allow_persistent,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET utf8;",
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true,
];
$this->db = new PDO("mysql:host=" . $this->db_data_dbhost . ";dbname=" . $this->db_data_dbname . ";charset=utf8", $this->db_data_username, $this->db_data_password, $pdo_attr);
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
To itterate some more, this is used on two API's at the moment.
One is consistently used by customers and never encounters this problem
The second is not used by a lot of customers yet seeing as this is still in development, it's only with a few customers for testing purposes. We do try to push an app to the appstore but it gets shot down by this problem. This API will eventually run into the error as depicted above and will not recover from this state without restarting/reloading the php-fpm service.
Using persistant connections is not that good (see why), but still, to solve this you may want to increase MySQL connections timeout.
To achieve this, see wait_timeout parameter for my.ini.
p.s. Also, you can catch this error and just reconnect to the database.
After much testing and research we found this bug was causing the issue:
https://bugs.php.net/bug.php?id=64549
Our solution was to use the error control operator '#' on the PDO connect:
$connection = #new PDO(
$connection_type.":dbname=".$dbname.";host=".$host,
$username,
$password,
[
PDO::ATTR_PERSISTENT => TRUE,
PDO::ATTR_TIMEOUT => 15,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET sql_mode='POSTGRESQL'"
]
);
If you are using your own error handler set_error_handler() you will need to ignore if error_reporting() level === 0.
// This handles the mysqlnd persistent connections bug when the # symbol is used it and the error is suppressed
if ( 0 !== error_reporting() ) {
// Do your regular customer error handling here
}else{
// ignore this since it is throwing a false positive from the persistent connection bug
}
I hope this saves someone hours troubleshooting. I hope the people behind PHP figure out a solution for this bug. It has annoyed many people for years.
Related
Had an issue recently where a major fire at a datacentre destroyed one of our machines. While this server is now offline all of the other servers on our network are still functional, although this has brought to light a problem that I'm hoping to find the answer for.
Is it possible to reduce the amount of time PDO will wait before reporting that the connection failed?
In my particular scenario there are others servers that rely on remote MySql connections to retrieve data from the destroyed server in order to display certain things. Now I have measures in place to handle the situation when the requested data isn't supplied, but have never had to deal with a machine being unreachable until now.
So right now I'm in the situation where my online servers are hanging on page load due to the destroyed server being offline.
Is there any preference or setting that can be provided when trying to make the initial remote connection where you say "return false without throwing a script breaking error after 5 seconds" for example?
I call my connections through a db class :
protected static function getDB()
{
static $db = null;
if ($db === null) {
$dbhost = DB_HOST;
$dbuser = DB_USER;
$dbpass = DB_PASS;
$dbname = DB_NAME;
try {
$db = new PDO("mysql:host=$dbhost;dbname=$dbname;charset=utf8mb4",
$dbuser, $dbpass);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo $e->getMessage();
}
}
return $db;
}
Like this...
$db = static::getDB();
I'm presuming that I can simply return false in the catch exception instead of echoing the error message which answers half of my question if true, but is it possible to speed up the time it will wait before throwing the exception in the event of an unreachable machine?
EDIT
I found this and tried it...
$db->setAttribute(PDO::ATTR_TIMEOUT, '5');
... but it makes no difference to the timeout whatsoever? Does this setting only relate to local connections maybe?
Just found the answer myself...
At first I found this and added it but it made NO difference whatsoever to the time taken before bomb out in my situation, maybe it works in others though?
$db->setAttribute(PDO::ATTR_TIMEOUT, '5');
But the answer that DID work for me was dropping this in right before the database connection :
ini_set("default_socket_timeout", 5);
Hope it helps somebody else.
I have the following code
function openDBConn($params){
$conn_mode = $params['conn_mode'];
$db_conn = $params['db_conn'];
//create connections
if(empty($db_conn->info)) {
$db_conn = new mysqli("localhost", $user, $password, "database");
$db_conn->set_charset('UTF8');
$mysqli_error = $db_conn->connect_error;
}
if($mysqli_error !== NULL){
die('Could not connect <br/>'. $mysqli_error);
}else{
return $db_conn;
}
}
//close db connection
function closeDBConn( $params ){
$db_conn = $params['db_conn'];
$db_conn->close;
}
//used as below
$db_conn = openDBConn();
save_new_post( $post_txt, $db_conn );
closeDBConn( array('db_conn'=>$db_conn));
From time to time, I get the "Could not connect. Too many connections" error.
This tends to happen when I have Google bot scanning my website.
This problem seems to have started ever since upgrading to MySQLi from MySQL.
Is there any advice on how ensure all connections are closed?
Thanks
You need to increase the number of connections to your MySQL server (the default is only 100 and typically each page load consumes one connection)
Edit /etc/my.cnf
max_connections = 250
Then restart MySQL
service mysqld restart
http://major.io/2007/01/24/increase-mysql-connection-limit/
Some hosters have a hard limit how many open database connections your are allowed to have. Maybe you want to contact your hoster to know how many you are allowed to open. For websites with hight traffic load more connections can be helpful.
Do you have access to the server directly or is it a hosted solution?
If you have direct access you can check the mySQL config files to see how many connections are allowed and increase it.
If you don't you might want to contact your webhost about increasing the limit and see if they will comply.
this post has been edited to reflect the findings thus far between myself and iamkrillin, as we have been the only two posters
I have the following VB.NET code connecting correctly, running from my PC
Dim strConnection As String = "Server=dev.xxxxx.vmc;Database=report1;integrated security=SSPI;" & _
"persist security info=False;Trusted_Connection=Yes;"
Dim ObjDa As SqlDataAdapter = New SqlDataAdapter(pStrQuery, strConnection)
Try
Dim dsReturn As DataSet = New DataSet
ObjDa.Fill(dsReturn)
ObjDa.Dispose()
Return dsReturn
Catch ex As Exception
Return Nothing
End Try
I have the following PHP code running from our iSeries
$conn = array( 'host' => 'dev.xxxxx.vmc',
'username' => 'vmc\adam',
'password' => 'xxxxxx)',
'dbname' => 'report1',
'pdoType' => 'dblib' );
try {
$db = new Zend_Db_Adapter_Pdo_Mssql($conn);
$db->getConnection();
} catch (Zend_Db_Adapter_Exception $e) {
}
The getConnection function, is throwing an error:
SQLSTATE[] (null) (severity 0)
And when I look up this error HERE, it appears to be a bug PRE 5.2.10, and we are running 5.2.17. But, some of the other comments say it is still a bug in 5.3.
*edit
It seems that if using a domain account, windows auth must be enabled. However, it is not through our PHP. So I need to set up a database specific user for our PHP connection.
In your VB snippet, you are connecting to SQL Server, and in your PHP snippet you are connecting to MySQL. If you need to use SQL Server from PHP, look at this. If you are on a non windows platform you can try FreeTDS. Here is an example of how to get started with it
I'm currently writing a PHP application and i noticed that my page loads kinda slow. I takes about 2 seconds (2.0515811443329 to be exact).
I've tracked down what the bottleneck was and it's the part where i'm creating a PDO connection to my MySQL database.
My 'connect()' method doesn't do any exoctic stuff. It simply looks like this:
public function connect ( $database, $host, $username, $password )
{
try
{
$this->db = new \PDO("mysql:dbname=".$database.";host=".$host, $username, $password);
if ( !$this->db )
{
throw new \Exception('Failed to connect to the database!');
}
$this->db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
}
catch ( \Exception $e )
{
echo '<strong>Exception: </strong>'.$e->getMessage();
return false;
}
return true;
}
So when i comment out the call to the 'connect()' method, then my page loads in: 0.035506010055542
This is a huge difference. I can imagine that creating a connection to a database does take up some time, but it takes more than 1,5 seconds... I'm not sure if this is normal?
If it is normal, that it takes up that amount of time then is there a way to store the database connection? Like putting it in a session? Actually, as far as i know storing it in a session isn't possible. But it would be the ideal solution. Storing the connection somewhere until the user closes his browser.
In anyway, is there a problem with my PDO / MySQL? And can i simply store the connection resource somehow? So that i don't have to reconnect to my database everytime for every new page?
PS. I'm doing this all on a localhost (Windows).
You're probably making a connection with 'localhost' as address. Try to change that to '127.0.0.1'. That should fix the problem.
You can create a persistent connection to database using PDO. From the manual
Many web applications will benefit from making persistent connections to database servers. Persistent connections are not closed at the end of the script, but are cached and re-used when another script requests a connection using the same credentials. The persistent connection cache allows you to avoid the overhead of establishing a new connection every time a script needs to talk to a database, resulting in a faster web application.
And example:
<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(
PDO::ATTR_PERSISTENT => true
));
?>
I'm trying to establish a PHP (5.2.6)/MySQL connection via mysqli.
error_log( sprintf( 'Querying %s:%s (%s) as %s/%s', DBHOST, DBPORT, DBNAME, DBUSER, DBPASSWORD ) );
$mysqli = #new mysqli( DBHOST, DBUSER, DBPASSWORD, DBNAME, DBPORT );
if( !$mysqli ) {
error_log( 'Unable to establish a connection to ' . DBHOST . '.' . DBNAME . ': ' . mysqli_connect_error() );
exit( 'Unable to connect to the db.' );
}
else {
error_log( '--> mysqli connection established' );
}
... more stuff ...
The result of this code is that the initial write to error_log happens (which validates that the constants are defined properly), but nothing else. Nothing. Everything just stops as far as I can tell. No unable to connect message, no connection established message. Just nothing. I can connect to MySQL directly using the parameters defined by the constants (copied and pasted from the log print).
I've read about the bug in versions of PHP prior to 5.2.9 and I've tried various ways of detecting an error, but there are no changes. Everything just stops and I'm starting to lose my mind trying to figure out what else I can do.
Has anyone ever seen this? MySQLi does seem to be installed--validated by its presence in the output of phpinfo() and by a test for function_exists( mysqli_connect ). Am I missing something obvious because I'm too focused on the details?
Any thoughts would be appreciated.
UPDATE
When I said, "I've tried various ways of detecting an error", I should have been more clear. No other variant included silencing output with the "#". Please don't focus on that. That was only included in my last attempt based on something read in the PHP docs.
So first, an apology. I'm working in an unfamiliar environment and didn't know that error logging was turned off. I turned that on via ini_set( 'log_errors', true ) and started getting the information that I need. I leave this just in case anyone else has a need to search the same problem.