Skip to content

Commit a52c751

Browse files
committed
[12.x] LostConnectionDetector and ConcurrencyErrorDetector
1 parent 95d6542 commit a52c751

File tree

8 files changed

+182
-88
lines changed

8 files changed

+182
-88
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Illuminate\Contracts\Database;
4+
5+
use Throwable;
6+
7+
interface ConcurrencyErrorDetector
8+
{
9+
/**
10+
* Determine if the given exception was caused by a concurrency error such as a deadlock or serialization failure.
11+
*
12+
* @param \Throwable $e
13+
* @return bool
14+
*/
15+
public function causedByConcurrencyError(Throwable $e): bool;
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Illuminate\Contracts\Database;
4+
5+
use Throwable;
6+
7+
interface LostConnectionDetector
8+
{
9+
/**
10+
* Determine if the given exception was caused by a lost connection.
11+
*
12+
* @param \Throwable $e
13+
* @return bool
14+
*/
15+
public function causedByLostConnection(Throwable $e): bool;
16+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace Illuminate\Database;
4+
5+
use Illuminate\Contracts\Database\ConcurrencyErrorDetector as ConcurrencyErrorDetectorContract;
6+
use Illuminate\Support\Str;
7+
use PDOException;
8+
use Throwable;
9+
10+
class ConcurrencyErrorDetector implements ConcurrencyErrorDetectorContract
11+
{
12+
/**
13+
* Determine if the given exception was caused by a concurrency error such as a deadlock or serialization failure.
14+
*
15+
* @param \Throwable $e
16+
* @return bool
17+
*/
18+
public function causedByConcurrencyError(Throwable $e): bool
19+
{
20+
if ($e instanceof PDOException && ($e->getCode() === 40001 || $e->getCode() === '40001')) {
21+
return true;
22+
}
23+
24+
$message = $e->getMessage();
25+
26+
return Str::contains($message, [
27+
'Deadlock found when trying to get lock',
28+
'deadlock detected',
29+
'The database file is locked',
30+
'database is locked',
31+
'database table is locked',
32+
'A table in the database is locked',
33+
'has been chosen as the deadlock victim',
34+
'Lock wait timeout exceeded; try restarting transaction',
35+
'WSREP detected deadlock/conflict and aborted the transaction. Try restarting the transaction',
36+
]);
37+
}
38+
}

src/Illuminate/Database/DatabaseServiceProvider.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
use Faker\Factory as FakerFactory;
66
use Faker\Generator as FakerGenerator;
7+
use Illuminate\Contracts\Database\ConcurrencyErrorDetector as ConcurrencyErrorDetectorContract;
8+
use Illuminate\Contracts\Database\LostConnectionDetector as LostConnectionDetectorContract;
79
use Illuminate\Contracts\Queue\EntityResolver;
810
use Illuminate\Database\Connectors\ConnectionFactory;
911
use Illuminate\Database\Eloquent\Model;
@@ -77,6 +79,13 @@ protected function registerConnectionServices()
7779
$this->app->singleton('db.transactions', function ($app) {
7880
return new DatabaseTransactionsManager;
7981
});
82+
83+
$this->app->singleton(ConcurrencyErrorDetectorContract::class, function ($app) {
84+
return new ConcurrencyErrorDetector;
85+
});
86+
$this->app->singleton(LostConnectionDetectorContract::class, function ($app) {
87+
return new LostConnectionDetector;
88+
});
8089
}
8190

8291
/**

src/Illuminate/Database/DetectsConcurrencyErrors.php

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
namespace Illuminate\Database;
44

5-
use Illuminate\Support\Str;
6-
use PDOException;
5+
use Illuminate\Contracts\Database\ConcurrencyErrorDetector;
76
use Throwable;
87

98
trait DetectsConcurrencyErrors
@@ -16,22 +15,6 @@ trait DetectsConcurrencyErrors
1615
*/
1716
protected function causedByConcurrencyError(Throwable $e)
1817
{
19-
if ($e instanceof PDOException && ($e->getCode() === 40001 || $e->getCode() === '40001')) {
20-
return true;
21-
}
22-
23-
$message = $e->getMessage();
24-
25-
return Str::contains($message, [
26-
'Deadlock found when trying to get lock',
27-
'deadlock detected',
28-
'The database file is locked',
29-
'database is locked',
30-
'database table is locked',
31-
'A table in the database is locked',
32-
'has been chosen as the deadlock victim',
33-
'Lock wait timeout exceeded; try restarting transaction',
34-
'WSREP detected deadlock/conflict and aborted the transaction. Try restarting the transaction',
35-
]);
18+
return app(ConcurrencyErrorDetector::class)->causedByConcurrencyError($e);
3619
}
3720
}

src/Illuminate/Database/DetectsLostConnections.php

Lines changed: 2 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Illuminate\Database;
44

5-
use Illuminate\Support\Str;
5+
use Illuminate\Contracts\Database\LostConnectionDetector;
66
use Throwable;
77

88
trait DetectsLostConnections
@@ -15,73 +15,6 @@ trait DetectsLostConnections
1515
*/
1616
protected function causedByLostConnection(Throwable $e)
1717
{
18-
$message = $e->getMessage();
19-
20-
return Str::contains($message, [
21-
'server has gone away',
22-
'Server has gone away',
23-
'no connection to the server',
24-
'Lost connection',
25-
'is dead or not enabled',
26-
'Error while sending',
27-
'decryption failed or bad record mac',
28-
'server closed the connection unexpectedly',
29-
'SSL connection has been closed unexpectedly',
30-
'Error writing data to the connection',
31-
'Resource deadlock avoided',
32-
'Transaction() on null',
33-
'child connection forced to terminate due to client_idle_limit',
34-
'query_wait_timeout',
35-
'reset by peer',
36-
'Physical connection is not usable',
37-
'TCP Provider: Error code 0x68',
38-
'ORA-03114',
39-
'Packets out of order. Expected',
40-
'Adaptive Server connection failed',
41-
'Communication link failure',
42-
'connection is no longer usable',
43-
'Login timeout expired',
44-
'SQLSTATE[HY000] [2002] Connection refused',
45-
'running with the --read-only option so it cannot execute this statement',
46-
'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.',
47-
'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Try again',
48-
'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known',
49-
'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo for',
50-
'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: EOF detected',
51-
'SQLSTATE[HY000] [2002] Connection timed out',
52-
'SSL: Connection timed out',
53-
'SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry.',
54-
'Temporary failure in name resolution',
55-
'SQLSTATE[08S01]: Communication link failure',
56-
'SQLSTATE[08006] [7] could not connect to server: Connection refused Is the server running on host',
57-
'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: No route to host',
58-
'The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior.',
59-
'SQLSTATE[08006] [7] could not translate host name',
60-
'TCP Provider: Error code 0x274C',
61-
'SQLSTATE[HY000] [2002] No such file or directory',
62-
'SSL: Operation timed out',
63-
'Reason: Server is in script upgrade mode. Only administrator can connect at this time.',
64-
'Unknown $curl_error_code: 77',
65-
'SSL: Handshake timed out',
66-
'SSL error: sslv3 alert unexpected message',
67-
'unrecognized SSL error code:',
68-
'SQLSTATE[HY000] [1045] Access denied for user',
69-
'SQLSTATE[HY000] [2002] No connection could be made because the target machine actively refused it',
70-
'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',
71-
'SQLSTATE[HY000] [2002] Network is unreachable',
72-
'SQLSTATE[HY000] [2002] The requested address is not valid in its context',
73-
'SQLSTATE[HY000] [2002] A socket operation was attempted to an unreachable network',
74-
'SQLSTATE[HY000] [2002] Operation now in progress',
75-
'SQLSTATE[HY000] [2002] Operation in progress',
76-
'SQLSTATE[HY000]: General error: 3989',
77-
'went away',
78-
'No such file or directory',
79-
'server is shutting down',
80-
'failed to connect to',
81-
'Channel connection is closed',
82-
'Connection lost',
83-
'Broken pipe',
84-
'SQLSTATE[25006]: Read only sql transaction: 7',
85-
]);
18+
return app(LostConnectionDetector::class)->causedByLostConnection($e);
8619
}
8720
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
namespace Illuminate\Database;
4+
5+
use Illuminate\Contracts\Database\LostConnectionDetector as LostConnectionDetectorContract;
6+
use Illuminate\Support\Str;
7+
use Throwable;
8+
9+
class LostConnectionDetector implements LostConnectionDetectorContract
10+
{
11+
/**
12+
* Determine if the given exception was caused by a lost connection.
13+
*
14+
* @param \Throwable $e
15+
* @return bool
16+
*/
17+
public function causedByLostConnection(Throwable $e): bool
18+
{
19+
$message = $e->getMessage();
20+
21+
return Str::contains($message, [
22+
'server has gone away',
23+
'Server has gone away',
24+
'no connection to the server',
25+
'Lost connection',
26+
'is dead or not enabled',
27+
'Error while sending',
28+
'decryption failed or bad record mac',
29+
'server closed the connection unexpectedly',
30+
'SSL connection has been closed unexpectedly',
31+
'Error writing data to the connection',
32+
'Resource deadlock avoided',
33+
'Transaction() on null',
34+
'child connection forced to terminate due to client_idle_limit',
35+
'query_wait_timeout',
36+
'reset by peer',
37+
'Physical connection is not usable',
38+
'TCP Provider: Error code 0x68',
39+
'ORA-03114',
40+
'Packets out of order. Expected',
41+
'Adaptive Server connection failed',
42+
'Communication link failure',
43+
'connection is no longer usable',
44+
'Login timeout expired',
45+
'SQLSTATE[HY000] [2002] Connection refused',
46+
'running with the --read-only option so it cannot execute this statement',
47+
'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.',
48+
'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Try again',
49+
'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known',
50+
'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo for',
51+
'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: EOF detected',
52+
'SQLSTATE[HY000] [2002] Connection timed out',
53+
'SSL: Connection timed out',
54+
'SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry.',
55+
'Temporary failure in name resolution',
56+
'SQLSTATE[08S01]: Communication link failure',
57+
'SQLSTATE[08006] [7] could not connect to server: Connection refused Is the server running on host',
58+
'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: No route to host',
59+
'The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior.',
60+
'SQLSTATE[08006] [7] could not translate host name',
61+
'TCP Provider: Error code 0x274C',
62+
'SQLSTATE[HY000] [2002] No such file or directory',
63+
'SSL: Operation timed out',
64+
'Reason: Server is in script upgrade mode. Only administrator can connect at this time.',
65+
'Unknown $curl_error_code: 77',
66+
'SSL: Handshake timed out',
67+
'SSL error: sslv3 alert unexpected message',
68+
'unrecognized SSL error code:',
69+
'SQLSTATE[HY000] [1045] Access denied for user',
70+
'SQLSTATE[HY000] [2002] No connection could be made because the target machine actively refused it',
71+
'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',
72+
'SQLSTATE[HY000] [2002] Network is unreachable',
73+
'SQLSTATE[HY000] [2002] The requested address is not valid in its context',
74+
'SQLSTATE[HY000] [2002] A socket operation was attempted to an unreachable network',
75+
'SQLSTATE[HY000] [2002] Operation now in progress',
76+
'SQLSTATE[HY000] [2002] Operation in progress',
77+
'SQLSTATE[HY000]: General error: 3989',
78+
'went away',
79+
'No such file or directory',
80+
'server is shutting down',
81+
'failed to connect to',
82+
'Channel connection is closed',
83+
'Connection lost',
84+
'Broken pipe',
85+
'SQLSTATE[25006]: Read only sql transaction: 7',
86+
]);
87+
}
88+
}

src/Illuminate/Support/Traits/CapsuleManagerTrait.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
namespace Illuminate\Support\Traits;
44

55
use Illuminate\Contracts\Container\Container;
6+
use Illuminate\Contracts\Database\ConcurrencyErrorDetector as ConcurrencyErrorDetectorContract;
7+
use Illuminate\Contracts\Database\LostConnectionDetector as LostConnectionDetectorContract;
8+
use Illuminate\Database\ConcurrencyErrorDetector;
9+
use Illuminate\Database\LostConnectionDetector;
610
use Illuminate\Support\Fluent;
711

812
trait CapsuleManagerTrait
@@ -34,6 +38,13 @@ protected function setupContainer(Container $container)
3438
if (! $this->container->bound('config')) {
3539
$this->container->instance('config', new Fluent);
3640
}
41+
42+
if (! $this->container->bound(ConcurrencyErrorDetectorContract::class)) {
43+
$this->container->instance(ConcurrencyErrorDetectorContract::class, new ConcurrencyErrorDetector);
44+
}
45+
if (! $this->container->bound(LostConnectionDetectorContract::class)) {
46+
$this->container->instance(LostConnectionDetectorContract::class, new LostConnectionDetector);
47+
}
3748
}
3849

3950
/**

0 commit comments

Comments
 (0)