1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-09-19 16:58:48 +02:00

Add retry loop when trying to establish db connection, log retries

Summary:
We retried if a db connection was lost when executing a query, but not when
establishing a connection. I've seen a lot of failures establishing connections
in our install (they go away when retrying), so this diff retries when
establishing connections, and logs when we retry.

Test Plan:
- Loaded phabricator in a sandbox
- Temporarily added a check in the try block to throw if there were still
  retries (to test logging, retry logic)

Reviewers: epriestley, blair

Reviewed By: epriestley

CC: aran, btrahan

Differential Revision: https://secure.phabricator.com/D1460
This commit is contained in:
Nick Harper 2012-01-19 15:04:38 -08:00
parent 27f52efd37
commit d5eaef9567
3 changed files with 43 additions and 25 deletions

View file

@ -117,6 +117,9 @@ return array(
// (e.g., db.example.com:1234).
'mysql.host' => 'localhost',
// The number of times to try reconnecting to the MySQL database
'mysql.connection-retries' => 3,
// -- Email ----------------------------------------------------------------- //

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -137,33 +137,43 @@ class AphrontMySQLDatabaseConnection extends AphrontDatabaseConnection {
'database' => $database,
));
try {
$conn = @mysql_connect(
$host,
$user,
$this->getConfiguration('pass'),
$new_link = true,
$flags = 0);
$retries = max(1, PhabricatorEnv::getEnvConfig('mysql.connection-retries'));
while ($retries--) {
try {
$conn = @mysql_connect(
$host,
$user,
$this->getConfiguration('pass'),
$new_link = true,
$flags = 0);
if (!$conn) {
$errno = mysql_errno();
$error = mysql_error();
throw new AphrontQueryConnectionException(
"Attempt to connect to {$user}@{$host} failed with error #{$errno}: ".
"{$error}.");
}
if (!$conn) {
$errno = mysql_errno();
$error = mysql_error();
throw new AphrontQueryConnectionException(
"Attempt to connect to {$user}@{$host} failed with error ".
"#{$errno}: {$error}.", $errno);
}
if ($database !== null) {
$ret = @mysql_select_db($database, $conn);
if (!$ret) {
$this->throwQueryException($conn);
if ($database !== null) {
$ret = @mysql_select_db($database, $conn);
if (!$ret) {
$this->throwQueryException($conn);
}
}
$profiler->endServiceCall($call_id, array());
break;
} catch (Exception $ex) {
if ($retries && $ex->getCode() == 2003) {
$class = get_class($ex);
$message = $ex->getMessage();
phlog("Retrying ({$retries}) after {$class}: {$message}");
} else {
$profiler->endServiceCall($call_id, array());
throw $ex;
}
}
$profiler->endServiceCall($call_id, array());
} catch (Exception $ex) {
$profiler->endServiceCall($call_id, array());
throw $ex;
}
self::$connectionCache[$key] = $conn;
@ -203,7 +213,7 @@ class AphrontMySQLDatabaseConnection extends AphrontDatabaseConnection {
public function executeRawQuery($raw_query) {
$this->lastResult = null;
$retries = 3;
$retries = max(1, PhabricatorEnv::getEnvConfig('mysql.connection-retries'));
while ($retries--) {
try {
$this->requireConnection();
@ -242,6 +252,9 @@ class AphrontMySQLDatabaseConnection extends AphrontDatabaseConnection {
if ($this->isInsideTransaction()) {
throw $ex;
}
$class = get_class($ex);
$message = $ex->getMessage();
phlog("Retrying ({$retries}) after {$class}: {$message}");
$this->closeConnection();
}
}

View file

@ -7,6 +7,7 @@
phutil_require_module('phabricator', 'aphront/writeguard');
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'storage/connection/base');
phutil_require_module('phabricator', 'storage/exception/accessdenied');
phutil_require_module('phabricator', 'storage/exception/base');
@ -15,6 +16,7 @@ phutil_require_module('phabricator', 'storage/exception/connectionlost');
phutil_require_module('phabricator', 'storage/exception/duplicatekey');
phutil_require_module('phabricator', 'storage/exception/recoverable');
phutil_require_module('phutil', 'error');
phutil_require_module('phutil', 'serviceprofiler');
phutil_require_module('phutil', 'utils');