Check for gone-away database server and reconnect

Should stop the worker process crashing if mysql closes the connection
due to timeout.
This commit is contained in:
2011-08-13 13:06:02 +01:00
parent 294679567f
commit fc33112097

View File

@@ -2,6 +2,8 @@
class SihnonFramework_Database { class SihnonFramework_Database {
const SQLSTATE_SERVER_GONE = 'HY000';
private $config; private $config;
private $dbh; private $dbh;
@@ -31,7 +33,7 @@ class SihnonFramework_Database {
$this->dbname = $this->getDatabaseConfig('dbname'); $this->dbname = $this->getDatabaseConfig('dbname');
try { try {
$this->dbh = new PDO("mysql:host={$this->hostname};dbname={$this->dbname}", $this->username, $this->password); $this->dbh = new PDO("mysql:host={$this->hostname};dbname={$this->dbname}", $this->username, $this->password, array(PDO::ATTR_PERSISTENT => true));
} catch (PDOException $e) { } catch (PDOException $e) {
throw new Sihnon_Exception_DatabaseConnectFailed($e->getMessage()); throw new Sihnon_Exception_DatabaseConnectFailed($e->getMessage());
} }
@@ -42,6 +44,16 @@ class SihnonFramework_Database {
$this->dbh = null; $this->dbh = null;
} }
protected function reconnect() {
$this->dbh = null;
try {
$this->dbh = new PDO("mysql:host={$this->hostname};dbname={$this->dbname}", $this->username, $this->password, array(PDO::ATTR_PERSISTENT => true));
} catch (PDOException $e) {
throw new Sihnon_Exception_DatabaseConnectFailed($e->getMessage());
}
}
/** /**
* Returns the value of the named item from the database configuration file * Returns the value of the named item from the database configuration file
* *
@@ -55,10 +67,27 @@ class SihnonFramework_Database {
return $this->database_config[$key]; return $this->database_config[$key];
} }
private function query($sql, $count = 0) {
$results = $this->dbh->query($sql);
if (! $results) {
list($std_code, $driver_code, $message) = $this->dbh->errorInfo();
if ($count == 0 && $std_code == static::SQLSTATE_SERVER_GONE) {
// Retry the query before failing
return $this->query($sql, ++$count);
} else {
throw new Sihnon_Exception_DatabaseQueryFailed($message, $driver_code);
}
}
return $results;
}
public function selectAssoc($sql, $key_col, $value_cols) { public function selectAssoc($sql, $key_col, $value_cols) {
$results = array(); $results = array();
foreach ($this->dbh->query($sql) as $row) { foreach ($this->query($sql) as $row) {
if (is_array($value_cols)) { if (is_array($value_cols)) {
$values = array(); $values = array();
foreach ($value_cols as $value_col) { foreach ($value_cols as $value_col) {
@@ -74,7 +103,7 @@ class SihnonFramework_Database {
return $results; return $results;
} }
public function selectList($sql, $bind_params = null) { public function selectList($sql, $bind_params = null, $count = 0) {
if ($bind_params) { if ($bind_params) {
$stmt = $this->dbh->prepare($sql); $stmt = $this->dbh->prepare($sql);
@@ -84,8 +113,14 @@ class SihnonFramework_Database {
$result = $stmt->execute(); $result = $stmt->execute();
if (! $result) { if (! $result) {
list($dummy, $code, $message) = $stmt->errorInfo(); list($std_code, $driver_code, $message) = $stmt->errorInfo();
throw new Sihnon_Exception_DatabaseQueryFailed($message, $code);
if ($count == 0 && $std_code == static::SQLSTATE_SERVER_GONE) {
$this->reconnect();
return $this->insert($sql, $bind_params, ++$count);
} else {
throw new Sihnon_Exception_DatabaseQueryFailed($message, $driver_code);
}
} }
return $stmt->fetchAll(); return $stmt->fetchAll();
@@ -93,7 +128,7 @@ class SihnonFramework_Database {
} else { } else {
$results = array(); $results = array();
$result = $this->dbh->query($sql); $result = $this->query($sql);
foreach ($result as $row) { foreach ($result as $row) {
$results[] = $row; $results[] = $row;
} }
@@ -111,7 +146,7 @@ class SihnonFramework_Database {
return $rows[0]; return $rows[0];
} }
public function insert($sql, $bind_params = null) { public function insert($sql, $bind_params = null, $count = 0) {
$stmt = $this->dbh->prepare($sql); $stmt = $this->dbh->prepare($sql);
if ($bind_params) { if ($bind_params) {
@@ -126,12 +161,19 @@ class SihnonFramework_Database {
$result = $stmt->execute(); $result = $stmt->execute();
if (! $result) { if (! $result) {
list($code, $dummy, $message) = $stmt->errorInfo(); list($std_code, $driver_code, $message) = $stmt->errorInfo();
throw new Sihnon_Exception_DatabaseQueryFailed($message, $code);
if ($count == 0 && $std_code == static::SQLSTATE_SERVER_GONE) {
$this->reconnect();
return $this->insert($sql, $bind_params, ++$count);
} else {
var_dump($std_code, $driver_code, $message);
throw new Sihnon_Exception_DatabaseQueryFailed($message, $driver_code);
}
} }
} }
public function update($sql, $bind_params = null) { public function update($sql, $bind_params = null, $count = 0) {
$stmt = $this->dbh->prepare($sql); $stmt = $this->dbh->prepare($sql);
if ($bind_params) { if ($bind_params) {
@@ -146,8 +188,14 @@ class SihnonFramework_Database {
$result = $stmt->execute(); $result = $stmt->execute();
if (! $result) { if (! $result) {
list($code, $dummy, $message) = $stmt->errorInfo(); list($std_code, $driver_code, $message) = $stmt->errorInfo();
throw new Sihnon_Exception_DatabaseQueryFailed($message, $code);
if ($count == 0 && $std_code == static::SQLSTATE_SERVER_GONE) {
$this->reconnect();
return $this->update($sql, $bind_params, ++$count);
} else {
throw new Sihnon_Exception_DatabaseQueryFailed($message, $driver_code);
}
} }
} }