Skip to content

Commit

Permalink
Merge pull request #718 from Tobion/retry-logic
Browse files Browse the repository at this point in the history
Identify retryable transaction errors
  • Loading branch information
deeky666 committed Jan 10, 2016
2 parents 3dcf0cc + 43f9275 commit a3a86aa
Show file tree
Hide file tree
Showing 12 changed files with 137 additions and 0 deletions.
4 changes: 4 additions & 0 deletions lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ abstract class AbstractMySQLDriver implements Driver, ExceptionConverterDriver,
public function convertException($message, DriverException $exception)
{
switch ($exception->getErrorCode()) {
case '1213':
return new Exception\DeadlockException($message, $exception);
case '1205':
return new Exception\LockWaitTimeoutException($message, $exception);
case '1050':
return new Exception\TableExistsException($message, $exception);

Expand Down
3 changes: 3 additions & 0 deletions lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ abstract class AbstractPostgreSQLDriver implements Driver, ExceptionConverterDri
public function convertException($message, DriverException $exception)
{
switch ($exception->getSQLState()) {
case '40001':
case '40P01':
return new Exception\DeadlockException($message, $exception);
case '0A000':
// Foreign key constraint violations during a TRUNCATE operation
// are considered "feature not supported" in PostgreSQL.
Expand Down
8 changes: 8 additions & 0 deletions lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ abstract class AbstractSQLAnywhereDriver implements Driver, ExceptionConverterDr
public function convertException($message, DriverException $exception)
{
switch ($exception->getErrorCode()) {
case '-306':
case '-307':
case '-684':
return new Exception\DeadlockException($message, $exception);
case '-210':
case '-1175':
case '-1281':
return new Exception\LockWaitTimeoutException($message, $exception);
case '-100':
case '-103':
case '-832':
Expand Down
4 changes: 4 additions & 0 deletions lib/Doctrine/DBAL/Driver/AbstractSQLiteDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ abstract class AbstractSQLiteDriver implements Driver, ExceptionConverterDriver
*/
public function convertException($message, DriverException $exception)
{
if (strpos($exception->getMessage(), 'database is locked') !== false) {
return new Exception\LockWaitTimeoutException($message, $exception);
}

if (strpos($exception->getMessage(), 'must be unique') !== false ||
strpos($exception->getMessage(), 'is not unique') !== false ||
strpos($exception->getMessage(), 'are not unique') !== false ||
Expand Down
31 changes: 31 additions & 0 deletions lib/Doctrine/DBAL/Exception/DeadlockException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\DBAL\Exception;

/**
* Exception for a deadlock error of a transaction detected in the driver.
*
* @author Tobias Schultze <http://tobion.de>
* @link www.doctrine-project.org
* @since 2.6
*/
class DeadlockException extends ServerException implements RetryableException
{
}
31 changes: 31 additions & 0 deletions lib/Doctrine/DBAL/Exception/LockWaitTimeoutException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\DBAL\Exception;

/**
* Exception for a lock wait timeout error of a transaction detected in the driver.
*
* @author Tobias Schultze <http://tobion.de>
* @link www.doctrine-project.org
* @since 2.6
*/
class LockWaitTimeoutException extends ServerException implements RetryableException
{
}
31 changes: 31 additions & 0 deletions lib/Doctrine/DBAL/Exception/RetryableException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\DBAL\Exception;

/**
* Marker interface for all exceptions where retrying the transaction makes sense.
*
* @author Tobias Schultze <http://tobion.de>
* @link www.doctrine-project.org
* @since 2.6
*/
interface RetryableException
{
}
2 changes: 2 additions & 0 deletions tests/Doctrine/Tests/DBAL/Driver/AbstractDriverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ abstract class AbstractDriverTest extends DbalTestCase
const EXCEPTION_TABLE_EXISTS = 'Doctrine\DBAL\Exception\TableExistsException';
const EXCEPTION_TABLE_NOT_FOUND = 'Doctrine\DBAL\Exception\TableNotFoundException';
const EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION = 'Doctrine\DBAL\Exception\UniqueConstraintViolationException';
const EXCEPTION_DEADLOCK = 'Doctrine\DBAL\Exception\DeadlockException';
const EXCEPTION_LOCK_WAIT_TIMEOUT = 'Doctrine\DBAL\Exception\LockWaitTimeoutException';

/**
* The driver mock under test.
Expand Down
6 changes: 6 additions & 0 deletions tests/Doctrine/Tests/DBAL/Driver/AbstractMySQLDriverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@ protected function getExceptionConversionData()
array('1569', null, null),
array('1586', null, null),
),
self::EXCEPTION_DEADLOCK => array(
array('1213', null, null),
),
self::EXCEPTION_LOCK_WAIT_TIMEOUT => array(
array('1205', null, null),
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ protected function getExceptionConversionData()
self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => array(
array(null, '23505', null),
),
self::EXCEPTION_DEADLOCK => array(
array(null, '40001', null),
array(null, '40P01', null),
),
);
}
}
10 changes: 10 additions & 0 deletions tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ protected function getExceptionConversionData()
array('-193', null, null),
array('-196', null, null),
),
self::EXCEPTION_DEADLOCK => array(
array('-306', null, null),
array('-307', null, null),
array('-684', null, null),
),
self::EXCEPTION_LOCK_WAIT_TIMEOUT => array(
array('-210', null, null),
array('-1175', null, null),
array('-1281', null, null),
),
);
}
}
3 changes: 3 additions & 0 deletions tests/Doctrine/Tests/DBAL/Driver/AbstractSQLiteDriverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ protected function getExceptionConversionData()
array(null, null, 'is not unique'),
array(null, null, 'are not unique'),
),
self::EXCEPTION_LOCK_WAIT_TIMEOUT => array(
array(null, null, 'database is locked'),
),
);
}
}

0 comments on commit a3a86aa

Please sign in to comment.