Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/Illuminate/Contracts/Database/ConcurrencyErrorDetector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Illuminate\Contracts\Database;

use Throwable;

interface ConcurrencyErrorDetector
{
/**
* Determine if the given exception was caused by a concurrency error such as a deadlock or serialization failure.
*
* @param \Throwable $e
* @return bool
*/
public function causedByConcurrencyError(Throwable $e): bool;
}
16 changes: 16 additions & 0 deletions src/Illuminate/Contracts/Database/LostConnectionDetector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Illuminate\Contracts\Database;

use Throwable;

interface LostConnectionDetector
{
/**
* Determine if the given exception was caused by a lost connection.
*
* @param \Throwable $e
* @return bool
*/
public function causedByLostConnection(Throwable $e): bool;
}
38 changes: 38 additions & 0 deletions src/Illuminate/Database/ConcurrencyErrorDetector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Illuminate\Database;

use Illuminate\Contracts\Database\ConcurrencyErrorDetector as ConcurrencyErrorDetectorContract;
use Illuminate\Support\Str;
use PDOException;
use Throwable;

class ConcurrencyErrorDetector implements ConcurrencyErrorDetectorContract
{
/**
* Determine if the given exception was caused by a concurrency error such as a deadlock or serialization failure.
*
* @param \Throwable $e
* @return bool
*/
public function causedByConcurrencyError(Throwable $e): bool
{
if ($e instanceof PDOException && ($e->getCode() === 40001 || $e->getCode() === '40001')) {
return true;
}

$message = $e->getMessage();

return Str::contains($message, [
'Deadlock found when trying to get lock',
'deadlock detected',
'The database file is locked',
'database is locked',
'database table is locked',
'A table in the database is locked',
'has been chosen as the deadlock victim',
'Lock wait timeout exceeded; try restarting transaction',
'WSREP detected deadlock/conflict and aborted the transaction. Try restarting the transaction',
]);
}
}
10 changes: 10 additions & 0 deletions src/Illuminate/Database/DatabaseServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Faker\Factory as FakerFactory;
use Faker\Generator as FakerGenerator;
use Illuminate\Contracts\Database\ConcurrencyErrorDetector as ConcurrencyErrorDetectorContract;
use Illuminate\Contracts\Database\LostConnectionDetector as LostConnectionDetectorContract;
use Illuminate\Contracts\Queue\EntityResolver;
use Illuminate\Database\Connectors\ConnectionFactory;
use Illuminate\Database\Eloquent\Model;
Expand Down Expand Up @@ -77,6 +79,14 @@ protected function registerConnectionServices()
$this->app->singleton('db.transactions', function ($app) {
return new DatabaseTransactionsManager;
});

$this->app->singleton(ConcurrencyErrorDetectorContract::class, function ($app) {
return new ConcurrencyErrorDetector;
});

$this->app->singleton(LostConnectionDetectorContract::class, function ($app) {
return new LostConnectionDetector;
});
}

/**
Expand Down
24 changes: 7 additions & 17 deletions src/Illuminate/Database/DetectsConcurrencyErrors.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

namespace Illuminate\Database;

use Illuminate\Support\Str;
use PDOException;
use Illuminate\Container\Container;
use Illuminate\Contracts\Database\ConcurrencyErrorDetector as ConcurrencyErrorDetectorContract;
use Throwable;

trait DetectsConcurrencyErrors
Expand All @@ -16,22 +16,12 @@ trait DetectsConcurrencyErrors
*/
protected function causedByConcurrencyError(Throwable $e)
{
if ($e instanceof PDOException && ($e->getCode() === 40001 || $e->getCode() === '40001')) {
return true;
}
$container = Container::getInstance();

$message = $e->getMessage();
$detector = $container->bound(ConcurrencyErrorDetectorContract::class)
? $container[ConcurrencyErrorDetectorContract::class]
: new ConcurrencyErrorDetector();

return Str::contains($message, [
'Deadlock found when trying to get lock',
'deadlock detected',
'The database file is locked',
'database is locked',
'database table is locked',
'A table in the database is locked',
'has been chosen as the deadlock victim',
'Lock wait timeout exceeded; try restarting transaction',
'WSREP detected deadlock/conflict and aborted the transaction. Try restarting the transaction',
]);
return $detector->causedByConcurrencyError($e);
}
}
76 changes: 8 additions & 68 deletions src/Illuminate/Database/DetectsLostConnections.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

namespace Illuminate\Database;

use Illuminate\Support\Str;
use Illuminate\Container\Container;
use Illuminate\Contracts\Database\LostConnectionDetector as LostConnectionDetectorContract;
use Throwable;

trait DetectsLostConnections
Expand All @@ -15,73 +16,12 @@ trait DetectsLostConnections
*/
protected function causedByLostConnection(Throwable $e)
{
$message = $e->getMessage();
$container = Container::getInstance();

return Str::contains($message, [
'server has gone away',
'Server has gone away',
'no connection to the server',
'Lost connection',
'is dead or not enabled',
'Error while sending',
'decryption failed or bad record mac',
'server closed the connection unexpectedly',
'SSL connection has been closed unexpectedly',
'Error writing data to the connection',
'Resource deadlock avoided',
'Transaction() on null',
'child connection forced to terminate due to client_idle_limit',
'query_wait_timeout',
'reset by peer',
'Physical connection is not usable',
'TCP Provider: Error code 0x68',
'ORA-03114',
'Packets out of order. Expected',
'Adaptive Server connection failed',
'Communication link failure',
'connection is no longer usable',
'Login timeout expired',
'SQLSTATE[HY000] [2002] Connection refused',
'running with the --read-only option so it cannot execute this statement',
'The connection is broken and recovery is not possible. The connection is marked by the client driver as unrecoverable. No attempt was made to restore the connection.',
'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Try again',
'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known',
'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo for',
'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: EOF detected',
'SQLSTATE[HY000] [2002] Connection timed out',
'SSL: Connection timed out',
'SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry.',
'Temporary failure in name resolution',
'SQLSTATE[08S01]: Communication link failure',
'SQLSTATE[08006] [7] could not connect to server: Connection refused Is the server running on host',
'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: No route to host',
'The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior.',
'SQLSTATE[08006] [7] could not translate host name',
'TCP Provider: Error code 0x274C',
'SQLSTATE[HY000] [2002] No such file or directory',
'SSL: Operation timed out',
'Reason: Server is in script upgrade mode. Only administrator can connect at this time.',
'Unknown $curl_error_code: 77',
'SSL: Handshake timed out',
'SSL error: sslv3 alert unexpected message',
'unrecognized SSL error code:',
'SQLSTATE[HY000] [1045] Access denied for user',
'SQLSTATE[HY000] [2002] No connection could be made because the target machine actively refused it',
'SQLSTATE[HY000] [2002] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond',
'SQLSTATE[HY000] [2002] Network is unreachable',
'SQLSTATE[HY000] [2002] The requested address is not valid in its context',
'SQLSTATE[HY000] [2002] A socket operation was attempted to an unreachable network',
'SQLSTATE[HY000] [2002] Operation now in progress',
'SQLSTATE[HY000] [2002] Operation in progress',
'SQLSTATE[HY000]: General error: 3989',
'went away',
'No such file or directory',
'server is shutting down',
'failed to connect to',
'Channel connection is closed',
'Connection lost',
'Broken pipe',
'SQLSTATE[25006]: Read only sql transaction: 7',
]);
$detector = $container->bound(LostConnectionDetectorContract::class)
? $container[LostConnectionDetectorContract::class]
: new LostConnectionDetector();

return $detector->causedByLostConnection($e);
}
}
88 changes: 88 additions & 0 deletions src/Illuminate/Database/LostConnectionDetector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

namespace Illuminate\Database;

use Illuminate\Contracts\Database\LostConnectionDetector as LostConnectionDetectorContract;
use Illuminate\Support\Str;
use Throwable;

class LostConnectionDetector implements LostConnectionDetectorContract
{
/**
* Determine if the given exception was caused by a lost connection.
*
* @param \Throwable $e
* @return bool
*/
public function causedByLostConnection(Throwable $e): bool
{
$message = $e->getMessage();

return Str::contains($message, [
'server has gone away',
'Server has gone away',
'no connection to the server',
'Lost connection',
'is dead or not enabled',
'Error while sending',
'decryption failed or bad record mac',
'server closed the connection unexpectedly',
'SSL connection has been closed unexpectedly',
'Error writing data to the connection',
'Resource deadlock avoided',
'Transaction() on null',
'child connection forced to terminate due to client_idle_limit',
'query_wait_timeout',
'reset by peer',
'Physical connection is not usable',
'TCP Provider: Error code 0x68',
'ORA-03114',
'Packets out of order. Expected',
'Adaptive Server connection failed',
'Communication link failure',
'connection is no longer usable',
'Login timeout expired',
'SQLSTATE[HY000] [2002] Connection refused',
'running with the --read-only option so it cannot execute this statement',
'The connection is broken and recovery is not possible. The connection is marked by the client driver as unrecoverable. No attempt was made to restore the connection.',
'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Try again',
'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known',
'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo for',
'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: EOF detected',
'SQLSTATE[HY000] [2002] Connection timed out',
'SSL: Connection timed out',
'SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry.',
'Temporary failure in name resolution',
'SQLSTATE[08S01]: Communication link failure',
'SQLSTATE[08006] [7] could not connect to server: Connection refused Is the server running on host',
'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: No route to host',
'The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior.',
'SQLSTATE[08006] [7] could not translate host name',
'TCP Provider: Error code 0x274C',
'SQLSTATE[HY000] [2002] No such file or directory',
'SSL: Operation timed out',
'Reason: Server is in script upgrade mode. Only administrator can connect at this time.',
'Unknown $curl_error_code: 77',
'SSL: Handshake timed out',
'SSL error: sslv3 alert unexpected message',
'unrecognized SSL error code:',
'SQLSTATE[HY000] [1045] Access denied for user',
'SQLSTATE[HY000] [2002] No connection could be made because the target machine actively refused it',
'SQLSTATE[HY000] [2002] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond',
'SQLSTATE[HY000] [2002] Network is unreachable',
'SQLSTATE[HY000] [2002] The requested address is not valid in its context',
'SQLSTATE[HY000] [2002] A socket operation was attempted to an unreachable network',
'SQLSTATE[HY000] [2002] Operation now in progress',
'SQLSTATE[HY000] [2002] Operation in progress',
'SQLSTATE[HY000]: General error: 3989',
'went away',
'No such file or directory',
'server is shutting down',
'failed to connect to',
'Channel connection is closed',
'Connection lost',
'Broken pipe',
'SQLSTATE[25006]: Read only sql transaction: 7',
]);
}
}